Servoy 8.3 launch part 3: Runtime customization
Servoy 8.3 launch part 3: Runtime customization
This is the final webinar in the 8.3 launch series. There are some more fixes and enhancements, so be sure to download and check out the release notes. One enhancement that we’re not showing here is in IDE messenger that we’ve added. And this came out of a discussion at the last Servoy world conference, which was sort of what’s the best way to reach our community. And since everyone in our community uses the IDE, we made a broadcast messenger kind of thing in the IDE. So now we can provide little updates that will notify you the first time you would launch and you get new notifications. So we can notify you when webinar recordings like this are ready or when new versions of components are released. We promise not to annoy you, but just useful stuff that hopefully you would want to know about. All right, with that said, let’s talk about today’s topic. We’re doing customization. In particular, the reason we’re covering this topic is because we brought back something called client design mode from, well, the other client offerings in Servoy such as Smart Client and Web Client. The classic Web Client have always had this, and this is sort of a drag and drop design mode of a form so that an end user can design his or her form. So as is the tradition with the tech webinar series, we will show some demos first and then we’ll review the steps and our demos include just a basic demonstration of what is client design mode and how to combine it with solution model to do real customization and also combining it with persistence. So saving the changes that your users might make. Otherwise, the next time they log in, it will be back to where they started. So let’s jump into the running web client. What you see here is a form of customers. They have lists of detail, quite simple. They can search that kind of thing. What we want to do is empower the user to be able to configure this form. Now just for demo purposes, I kept this pretty simple, but you can imagine that there’s a lot more possibilities. So I’m going to click my pencil here and you can see that the UI of the form changed here a bit. I have the dashboard around the fields. When I mouse over the fields, I get a different cursor. I can click on a field and select it. Let’s say that I want to resize it and maybe I’m going to put address and city over here. You can see that I’m moving the label when I drag the field. Also, I did a little bit of grid snapping here so that these are all kind of lined up. Let’s say that I’m really happy with this. Then I want to save this. Now you can see that the form has been saved. Not only has it been saved in this session, but if I log out of my application and come back, you can see that is now in the way that I’ve customized it for myself. This wasn’t sort of a developer save. This is a save just for this particular user in this case. Of course, customization might be at a tenant level or some other kind of level. That’s really up to you. Let’s do another example of this. I have here the products list in the products detail. On purpose, I have a very bare bones view of the product detail. Let’s say that I want to put this in designer. This time, I’m going to select something and double click. I don’t like these labels. First of all, they’re kind of ugly. They’re not real words. I’m going to double click and open up a little properties editor and change my label. Let’s just call it product. You can see the label changed. Here, I have a category ID and end users don’t really like to just try to guess foreign keys. Let’s change that as well. I’m setting the value list here to categories and we’ll do the same for suppliers. Let’s say the unit price we want to format that and we could come in here and do a more standard numeric format for currency or something. Once I save that, you can see that now the value list is applied to the category in the supplier. My nicer label for product was applied and also the format was applied for the unit price. Let’s say that I wanted to also configure the fields in what fields are on the form. I’m going to show a little field choosier here and get a list of all the fields for the table. Let’s say that we’re sort of restarting here. I’m going to maybe pick some different fields to do okay. Once again, it’s, I should probably leave it in a design mode. I’m free to continue to design this. I combined a bit of solution model in this case to put the fields on the form, but then I also put it in design mode so that I can begin to design what the screen is going to look like for myself. Okay. Also with solution model, you could create forms from scratch. You can create anything that’s there with the solution model and that’s a different topic and we plan to do a webinar on that in the future. But just to give you an idea, I’m going to try this. I’m not sure it’s going to work, but I’m also going to build a form from scratch so I’m going to choose my data source maybe it’s based on orders. And now it’s looking at what’s in the order table. Then maybe we’ll just get a few fields here. Something like that. And you can see that now I have a form here ready to be customized. And I could go in and say put the employee value list here. And you get the idea. So that in that case, the form was not even built at design time. It was generated a runtime and I put it into design mode to allow the end user to customize it. Let’s go into the IDE and take a look under the hood. I’m going to first take you to a base form that I made because I showed you multiple forms. I should probably close all these because I showed you multiple forms. What I did is encapsulated all of the logic for the design mode stuff into a single form. I called it designable. You can see that it has no UI. But if I open this in the script editor, you can see from the outline here I put quite some methods in. And the first one that I would draw your attention to is when I clicked that pencil icon was my start design. And it’s this line here controller.set design mode that actually puts that form into design mode. In which case then the fields are no longer available for input. The elements are to be available for design. What you do is you pass in some event handler. There are some callback events when you’re in design mode. Drag drop, select resize, double click, and right click. You can handle any or all of those events to build your own custom experience. Another thing I did is I decided which fields I wanted to be designable. I just made it so that I would make the fields designable and let the labels follow them around. That was a custom experience that I made up. So I wrote this private method just to get designables. And it was just returning the fields only. But the line I would draw your attention to is here where I just add the style class. You’ll notice that when I entered design mode, they got that sort of dashboarder and my exit to design mode it went away. So you can see down here in the stop design method, I set client design mode false. And then I removed the custom style classes that I had added. The next event that I would draw your attention to is the on select. This gets called when I actually clicked on the element in the form. And you’ll notice that it got the little handles around it. Also the style change that became highlighted. That was something that I did that’s not baked into it. So what I’m doing here is I’m removing the selected style. And I’m adding the selected style for the new selected component. And I have a private method here called get component where it takes the event and it pulls the component off the event. But essentially it’s passed in. I’ll show you that. It’s passed in as part of the event data object. It could actually be an array of selected components on the select event. So that’s why I got the first one that’s only doing one here. So that’s why the style change. The next thing that we did is we actually moved the component. So I’ll bring you to the on drag handler. Sorry, that just does, I didn’t do anything there. I just allow you to move it. But you could prevent certain components from moving if you want that way. Or you could save a save a location so that you could recall it later. We know the starting location if you wanted to undo a single drag or something. If it didn’t drop in the right place. So there’s lots of options there. But in my case, I just let you drag it anywhere. Then we drop the component. And again, I use my get component event to find out which component was dropped. And then I wrote a couple of private methods to snap the location, which really just moves it to the nearest 10th pixel x and y. And then the other method that I had was to bring the label along with it. And I really just sort of copy the the x location of the label over and put it above, keep it above the component. So that’s also like a custom kind of thing. The next event that we can handle is the resize. This gets called when the component is being resized with or height. In my case, I’m just snapping the width. I’m not bothering with the height for this example. So similar thing. I just wrote a little private method to snap the width. And again, this is in a base form. So this would apply to any form. Just to turn on a little bit of snapping because I think that’s nice if you’re dragging things around. Then the other, it’s not really an event, but the next thing we want to do is we want to sort of save the changes. So once you do something in design mode, if you put it back out of design mode, it’ll actually revert to the way you had it because it’s just sort of allowing you to change the runtime setting. And when you exit it’ll just revert it. What we really want to do is put it down into the solution model so that the sort of the blue print of the form is modified, at least for this client session. And so what that looks like is I have a method here called save. And this gets called when I clicked that checkbox after I was in design mode. And what I’m doing is I’m iterating over my components and I sort of call this recurServoy and I save the component. And really what I’m doing is I’m copying the runtime information such as x, y with height into the, into the, the JS component, which is the solution model component. So that sort of puts it back into the form blueprint. It’s important to call this right here though, controller recreate UI because that’ll actually then take the change to the blueprint and update the runtime form UI. So that part is important if you want to see the changes reflected after you, after you save. The other thing I showed you was the, when we double clicked a component, I was showing a dialog and for that I just handled the double click event. Again, all of this was passed in when we put the set design mode on the, on the form. And so this is the callback and the, for the component that’s clicked, I’m, I made a custom little form that shows in the dialog and I just call, I made an open method where I pass in the component. And it just sort of copies everything into those form variables and, and so when you save it writes a fact of the component. Then finally, what we want to do is at the end of all this, we want to, we want to persist the changes so that the next time the user logs in, shear, he gets the, the same setup that they made. And this would be unique to that user. This of course doesn’t really have anything to do with client design mode, but, you know, to make these out, make the example complete, I wanted to show you that. And in this case, I’m using web storage. You could of course store it in the database. And we had a whole other webinar where we introduced the web storage service for the ng client. I have a method here persist, which gets called after the save. And what I’m doing is just building up a little object called form state. And again, I iterate over the fields that I had designed. I also grab, I wrote a little private method to get the label for the field. And I have a, an inner function here to persist the component. And it’s just writing some of the information to the form state, x, y with an height, for example. And at the very end, what I’m doing, this is the important line is calling the local web storage and we make some more room. And I, I give it, have to give it a unique key. So I’m just doing form state dot and then the name of the form. And then, and then I stringify that object. So I convert it to Jason. So if we actually look in our browser here, doesn’t matter where because this is just looking at web storage and go to the application tab, you can see the different keys that I put in here, customer detail, orders and product detail. So even that, that one that I just made that was, that was brand new, has been persisted. And you can see that the value here is just the components and their locations, et cetera. So that’s a, that’s a good strategy for, you know, if you just want to say this now, if this user logged in from another machine, they, they wouldn’t get this because this is just stored in their browser. And that’s up to you. Something’s like this would be nice to just keep at the browser lever other things you could, you could put in a database. All right. That pretty much concludes the demo side of this. Let’s get back to a few slides just to sort of recap everything and simplify it down a bit and then we’ll take some questions. So step one is to enter client design mode. This is done on the controller object of the form. And when you set design mode, you can pass in the handlers. I should point out that this is an overloaded method, meaning you don’t have to implement all the handlers. You could just pass in on, on dragon on draw person, for example, you don’t have to handle all of them. But in my case, I handled everything but right click. Then the first event that we dealt with was the selection event in the demo. This was when I clicked on the element and it turned yellow. And in my case, remove the last style class and I added the style class to the newly selected component. So deselecting one and selecting the other one. This is just a visual thing. I could also show you the style sheet real quickly for that as well in the IDE. It is designable dot CSS. And so this is all I put in that style sheet. It’s not like I was doing any CSS crazy stuff. I just made one class for all the fields that are designable that have that dash border. And then I had the selected one, which just had the background that was highlighted. And this one inherits this one. So it’s dealing with both. So when we were dragging the component and we dropped it, this drop event got fired. And again, all of these events just passed in an event. And you’ll notice on every one of these, I’m pulling the component that was affected out of the event dot data property. And in this case, I just applied some snapping to the nearest tenth pixel. You do have to go application up to EY when you’re in design mode. I noticed to sort of see what you’ve just done to the runtime component. We do the same thing with resize. So we’re snapping the width. I didn’t bother with the to the nearest tenth pixel. You can handle the click events. So I handled double click. And I made a to sort of a custom form that I show in a dialogue. And I passed in the component to sort of further edit that component. And that’s how I was able to change the value list and the format, etc. When you want to apply the changes back into the client, not talking persistence yet, but back into the client, you have to push that back into the solution model. It’s not enough that you just leave it as the runtime element changes because the moment you exit client design mode, it’ll just revert. So when you want to save the changes, you somehow have to copy them back into the original JS components and JS form. So you can see I did a bit of solution model here to get the component reference. And then I’m just setting x, y width and height. If you want to see the changes then in the running client, after you exit design mode, you got to call this controller recreate UI. That sort of pushes those changes from the blueprint back into the runtime form. Persistence is the way that you get this each time you log in. And I just elected to do web storage. This is really up to you. You could do it in database fields and database columns, or you could serialize it like I did into the browser and just a simple object and we used the JSON.stringify. When the form loads, I read it back from web storage. So on form load, I’m calling this private method called loadform state. And again, I use that key form state dot form name. And I then read it in. This is a typo on the slide. JSON.stringify should be JSON.Pars. And then you can see that I’m copying it from the component state back on with component. At the end of all this, you would want to call recreate UI too if the form’s already been shown. So that’s pretty much the overview. One last thing that I would point out is that, again, I used form inheritance there in this one form called designable, where I put all of these methods in and sort of made this custom design experience so that it can be propagated across any number of forms. And the one example I showed I dynamically created everything with the solution model. I don’t think it’s important to show you the code for that. Just at the end of it, I still put it in design mode and I still persisted the changes. So we see requests a lot for in terms of use cases for applications where the end users can really pick a table, pick some fields, maybe pick some related information, drop it on a form, arrange it, set some filters, that kind of thing, and really have sort of like a low level data access kind of experience. And it’s possible with that. I’ll leave up these useful links. These are the typical links we have. It includes also a link to the wiki which has more info about client design mode. And Steve, do we have any questions? Yes, we have a few questions. One of the questions, does this also work with custom controls? Which of which custom controls? I guess that. I guess maybe web components probably. Okay. Yeah, it does actually. A web component is, I mean, even that Servoy default components are really just web components. They have the same set up. So now the experience that I built doesn’t account for web components. And I really limited it to just fields to keep it simple. But yeah, if you had put a Google map or something on the form and you wanted to drag it and resize it and persist it, that would work because every web component has the location property. Sure. That’s the best property. Chris, this other question which I think may have been answered. This could be catch the design events in order to add our own functionality to, for instance, create a new field on the fly and add it to the form. Yeah, I showed an example of that where I sort of reset the form, but it could have been additive. You know, like I click the button, it showed that dialogue with the field chooser. I checked the fields that I want. And then it those were dynamically added to the form. They did not exist in the form in the form of design time. Several people asked if this works with responsive forms. No, it does not. That would be quite challenging to even think about how to make that. Now, what types of elements are supported and could resize a tablet panel or a container? Yeah, all components have at least a size property and a location property in absolute layout mode. Therefore, when you, and I didn’t really investigate this too much, but I did play around with like a few bootstrap extra components that I had on the form. You could resize them and drag them around. Although, depending on the components, I might not have the effect that you want. For example, the height might be controlled by a property, not the like a CSS property or something and not the location, which might be ignored. Steve asked, can you adjust the nearest 10th pixel to some other larger number? I think you can. You showed the 10 was just a number that you put in the method there. Yeah, yeah, absolutely. That was totally arbitrary. I probably should put that in a variable in the form and called it like snapping size. So you could change the variable in one place. It seems like programmatically it would also be easy to have a checkbox for enabling snapping if the person didn’t want that. Then you would just again, because I was all handled in a method, you could just either have it or not, if you so desire. Yeah, yeah, the bottom line is that it’s sort of a low level kind of API. So it’s up to you how you want to design the experience and anything that is flexible like that is usually more work. You’ll notice that this wasn’t like the simplest that that base form wasn’t the simplest base form in the world. It took me probably four or five hours to make make that and test it. So it requires a little bit more expertise and a little bit of playing to get the experience that you want. The good news is that that’s sort of a one-time investment if you’re using form inheritance. And then once you get that experience right, then you can propagate that throughout the form of application. Will this demo be available? Yeah, at the end of this week, we’re going to release all of the recordings of this webinar. Where applicable, I will post the example solutions on the form that we have a regular form thread. So there’ll be there for download along with the slides. And we really encourage you guys to download the new version and test it out and to give us feedback on the form, especially for for this webinar. And let’s see. There’s another couple of questions. Chris also asked, what about subforms? Can you put the subform in your side mode? A subform meaning an inherited form or a subform meaning like an inner form. I’m not sure. I’ll answer both. Inheritance is form. Interform. Yeah. So a client design mode does have the limitation that only one form can be in design mode at a time. In the example that I showed, in fact, the the outer form, I’ll switch back to it. You know, this is a form with really two forms in a split panel, right? Sure. The list over here and the detail over here. And the outer form is the one where it’s being called. What I’m doing is actually telling this inner form here to go into design mode. But I couldn’t put this other form over here in design mode at the same time. I’d have to do it, you know, separately. Got it. And what about I 18N? What about it? I’m not sure. I mean, I 18N is if you, is that something you’d have access to if you wanted to change the language of a label or something based on? Oh, yeah, absolutely. Okay. Yeah, I understand the question. In fact, you might notice that when I, when I did the field chooser thing here, no, I didn’t, I didn’t take, oh, yeah, I actually, it’s not, you can’t see it, but I actually looked at the title property of the columns, not just the name of the column, but I didn’t actually set the title property. So that if you had an I 18N string in the title property on the, you know, the column metadata in this example, it would have filled in. But again, that’s all, that’s all how you design the experience. So in general, in Servoyanywhere, you can show text, you can show translated text no matter what. Okay. The last question is, when is the 8.3 final available? I believe it’s coming pretty soon. I thought Johan posted that it’s out today. I don’t know. I was so busy working on this. Johan posted that it is out today, ignoring all of this. As far as I know, Servoy8.3 final is available today from our download site that download.sirboy.com and it’s based on the RC2 fixes. So there may be more, there may be an 8.3 one fairly soon, but we encourage everybody to download it today and give it a try. Yeah. Yeah, just looking forward a bit here. You could see that already next Wednesday, we have another tech webinar, although this is more of a target to the progress community. So of course, this might not be applicable to you at all. If you’re not using a progress backend, that will be all about integrating ABL business logic. And then a couple weeks after that, we go back on track with another tech webinar for the whole community and we’re hopefully going to be giving an update on the AG Grid project and some component availability is there. So look forward for that. And thank you guys for attending. Well, thank you. And for those observing, happy Star Wars day. May the fourth be with you. And we’ll see you next time.