ArcGIS API for JavaScript: Building Your own Widget

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone and welcome to building your own widget with the ArcGIS japi I am JC Franco and I'll be co-presenting with Matt Driscoll we are both developers in the jsapi we work on widgets and all sorts of UX and UI related stuff and let's get started so for today's agenda we'll be setting up the developer environment with typescript and the JavaScript API and then we're going to be showing you how to create out custom class and then after that we're going to go into developing a simple widget and then finally we'll combine all this to create our final widget so in terms of setting up the developer environment we'll be focusing on setting up the JavaScript API along with typescript in the next steps if you're not familiar with typescript just like its name implies its type javascript and what this really means is that with typescript we are able to define the shapes of our objects or functions and this has a few benefits one of the main ones is that it'll help you catch there's earlier for example type triple complain if I take a look at this snippet here where I'm defining a person with a name in H and later on I define one if I try to assign a string to a property that we know is of type number type strips going to complain and catch that error similarly if I try to assign the number 12 property that doesn't exist typescript catches that and it's really useful because I don't have to wait until runtime to catch all these errors and it also helps us keep the code really self-documenting and what I mean by that is say I define a greet function with an argument of type person later on if I'm using the function most of the IDS now have support to give you some sort of intellisense and in this case it'll tell me that it's expecting a type person object to be passed to this function so just by looking at the hints that the ID gives me I am able to kind of learn more about how the API different objects or functions that I type type script allows me to learn them way faster without actually having to create any sort of documentation another neat feature is that typescript allows us to use JavaScript features that are being added to modern browsers and we are able to leverage in older browsers because typescript will compile in to code that older browsers can understand here are a few examples of these there's land costs which are ways of defining variables and gives you the option of whether you want to allow a variable to change or just a fixed or constant like its name implies then we have fat arrow functions which are a very simple way and concise of defining functions we also have templates strings which are very useful because they allow us to use variables in line in the string itself so it's very readable and very concise another feature is the structuring which allows you to assign in single line different parts of an object or different items from an array so in this example here from the people array I am taking the first item or person and I'm assigning the name in each property's two variables or costs that have the same name so name and age similarly there is property shorthand which is a neat way of defining a property if the value has the same name these are some of the features that you can use that are part of modern browser API set will still work in older browsers typescript is also supported on a wide variety of IDs so it's very easy for you to jump in and start using typescript so give it a try for first demo we'll be showing how to set up your dev environment to work with the JavaScript API and typescript so let's take a look at my index page and it's a very simple one in all that I'm doing is bringing in some CSS the Jace API along with some configuration and then I have a div here for a view and I'm importing my demo application and we'll get to that in a few but first let's set up our project first off we'll go into the project directory then we'll initialize the project with defaults and all this is doing is it's creating a default package JSON with some placeholder values and you can populate later on and what this means is that we can install typescript along with the JavaScript API types and what this is doing is my default typescript does not know what the J's API structure of objects or classes looks like so that's why we need to bring in the types once we've done that we can initialize our typescript project after we do this the typescript compiler is going to create a default TS config JSON that has all sorts of options here along with some documentation on what all these mean but for our purposes we are going to use a subset of these that you can find on the typescript setup page as part of the javascript api is sdk so we are going to take this configuration and copy it over and then i'll be running the typescript compiler and enable watch mode so that anytime i change a file it's going to compile the code so let's go back and take a look at our main application i've got i had added some code here that I'll start on commenting as I do that you can see typescript is bringing up some errors because it doesn't know what map is so let's take care of that import and once I do that my IDE can suggest different properties that belong to map and another neat feature is say I define a map view my D can suggest the import that I need that's pretty cool and once I do that I same with map I have access to all the properties that are supported in map view so as I'm doing that top script is compelling in the background and if I check the demo application that I have here we should see our simple app running with a map so let's recap we went through the steps that you need to take to setup typescript along with the JavaScript API typing's and then after doing so we were able to build a very simple mapping application this wraps up the first part and with that I'll hand it off to Matt thanks Franco so now I'm going to show you guys how to create a class in our API and we'll be using this class later as a view model for our widget so all the classes in our API extend this ESRI core accessor class so this is a API foundation for our class for our API and what it does is provides a consistent developer experience for example let's say I create a class called person and I have a couple of properties name and age I can easily know that I can watch the age property and then call some kind of function so I don't have to look at the API Docs to figure out if there's some kind of event for when an age changes I know that all the properties in our API can be watched and setting a property and getting a property is very simple and straightforward I would just call you know me dot set age equals whatever so it's it provides a really good experience for users it's a little background on what we'll be creating here's an ArcGIS online item and if you'll notice here on the right side there's a score indicator for how well this item is filled out and you can see this one has a really high score because it has a lot of content to find there's things like the metadata that's all filled out it has like the terms and all kind of stuff and you can see in for more information about how this score is calculated by you know this this one has a summary a thumbnail description title tags etc so what we'll be doing is creating a widget that does sort of this but in a little different display so a little background about what we're gonna be creating we need a class that loads a portal item it allows editing that items properties it will highlight the items score and provide suggestions on how to improve that score and save an item as well so that's the requirements forward the class we're going to create so let's look at the item structure so here's the portal REST API for an item and you can see some of the properties it has like an ID the owner a bunch of dates titles URLs and down here at the bottom there's one for score completeness and this gives information about the item the item score based on you know what information is filled out so we'll be using this to kind of drive our class and then in the JavaScript API we have a portal item and this has properties as well and it has a property to get all of the information from the portal item and that's where we'll be getting the score so there's I think there's a source property ya source JSON property or we can get all that information from so we're using this portal item to load and save any properties that we change so we're working through this through the API so here's what we want the interface for our class which we're going to call item score this is what we need to have in there so we'll have a property for defining the portal and if it's not defined we'll just use the default arcgis online portal then we'll have a property for specifying the item ID so this will be able to grab the item information using this item ID then we'll have a read-only property called suggestions and this will be determined by the score and what things we can do to improve that score so when a user sets an item ID and loads it then it'll calculate the suggestions and the score then we'll have a few properties that the user can set and get to update the score and that'll be things like the title summary description tags terms of use and thumbnail and then we'll have a couple of methods one will be to load and so load D item and all of its information and calculate the score and then want to save which will update any of these properties that change back to the portal item so cool oh and so now let's get into the demo so currently I have this basic class setup and I have a global variable in the window or I can look at it and you can see it's extending access err but it doesn't have any properties or things set up let's look at the code for that so here's my main type script file I have I'm importing an item score this will be the custom class that I'm going to use and then I initialize it and then I store a reference to it in the window so I can access it through the console and then in my class it's basically just a simple frame of a class I'm importing access err because it's going to extend that it's importing a few decorators because we're going to define a property and then we need to declare it here so we declare it as item score and it extends access err and then we have a few placeholders where we're going to put our lifecycle methods any variables properties public methods and private methods so that's it so let's start building out this class so the first thing we're going to want to do is load some dependencies so we'll import those at the top here and we know we're going to need a reference to portal because one of our properties is going to be for the portal so we got to import that as well as a portal item and then we'll have some interfaces for the items core properties and suggestions and then we'll need to define an error and at some point if something wrong so we're going to import the Azeri korero class and then we're going to use as we request to make any Network calls for loading and saving so now let's add a private variable this will be for the item so once we load the item ID we can store the item as a private variable and this will be a portal item type then let's start adding some properties so I'm just gonna add all of our properties that we need for this class and I'm gonna walk through them so the properties we're going to need are going to be the portal and by default it's going to use a default portal then we're gonna create a property for setting the item ID and this will determine which items a load from the portal and this will be undefined by default then we're gonna have a description and this is going to be an alias property which means it's just going to point to the items description so we can just get a quick reference of it without having to go through the item and this will be an instance type of portal item description and then we have another alias property which instead of having to go through the items source JSON to get this we just alias it as score and this is gonna be a read-only property so user doesn't update this it's just going to be calculated from the score on the out port on the portal item so we don't leave score and this will be a number then we have summary and this is just another alias property same with suggestions and this is I'm gonna be read-only and calculated from the item score on what things to improve so this would be an array of suggestions then we have tags and so this is the tags for the item which I'll use your word set to get a better score another alias property at least property terms of use so this is the licensing information of the on the portal item so user can set this to get a better score thumbnail which would be a blob type so the same thing someone can update this get a better score for their item title another alias property use your gonna update get a better score so the metadata for the item the next thing we're gonna want to do is set up our constructor so we go up to our lifecycle methods constructor which is just going to take in these item score properties which we're defining an interface which you know basically they set the portal and the item ID and then here's the interface for our suggestions it's going to be have a property and the type which either is going to be add or enhance it so now we want to create our public methods this will be our save and load methods so go into our section for public methods and we're going to create a method to save so this will save the portal item if it doesn't exist if the item is not there it's going to throw an error you can't save it otherwise it's gonna take the item we're just a JSON and update the item update to something L if it needs to and set the suggestions on what needs to be updated still and then we have our load method which is going to grab the item ID but if there isn't one it's gonna throw an error and then otherwise it's going to set the item to a new portal item load that item and then generate the suggestions based on the content of that item so you see it doesn't know about these private methods or view item and so we need to add that so we'll add this into our private method review item and this is going to be like the meat of determining what things - what suggestions we can do to enhance our item so we get a reference to all the metadata we want to calculate we're gonna have a list of suggestions and then if you know they're not a summary we're gonna suggest to add a summary otherwise if the word count isn't very high we're gonna suggest to enhance it and we do that for a description as well tags thumbnail if there's not a thumbnail you know we should add one in terms of use and title so cool so I have type script watching a file structure so it compiles so this should be updated now so if we go into this class I do I'm score I can see that there's no item set but there is a portal and if I set an item I should better get these scores and item descriptions and stuff but you see the properties are there now in the class so that's good so what I want to do is I can do item score download and it's going to throw an error because we don't have an item ID set but you can see that the method is working correctly and that error is being defined right so what I can do to test out this class is I can set an item ID so I have toward item ID equals this string for and a portal item and then I can do item score download now and now you see it did a promise and it should have loaded it so I can do item score log it out and now the item is defined and I can see information about that portal item and it has a description it's that one I showed it's the item I showed earlier that was had a high score so you can see that the score is 100 and I can see like the summary if there's any suggestions this one doesn't have any because it's got a high score and then all the information that we were going to have a user set so cool so our class is setup now let's go back here so what do we learn we learned how to implement this item score class by extending as a Recor accessor we created some properties using the property decorator we typed constructor arguments and we created both public and private methods so now let's talk about writing a widget so what our widgets well widgets are basically pieces of user interface and they perform some sort of function or display some sort information and they're usually interactive so a user can you know click on them or do something with them and they usually have some kind of state to so that they're either maybe in a loading state or you know the user clicked on it and if now it's in a different state altogether so why would you use a widget well you can reuse it in multiple apps or multiple times in the same app it makes code more modular so things are kind of bundled and put together and they help you build more complex apps by using them so they interact with each other and makes it easier to create an application so creating a widget in our API you would extend the base widget class which is ESRI widgets widget so it's the base class for creating a widget view it also extends the ESRI core accessor class so you can watch properties set properties and as long including that you also get a lifecycle in the widget base class so here the main lifecycle method you get in the class you get a constructor where you can define things upon initialization of that widget there's a post initialize or you want to may want to do things after it's been constructed but before render is called the first time then you have the render lifecycle method and this is where you define your user interface through JSX and virtual DOM and then destroy or you can clean up any event handlers or just get rid of anything that you don't need anymore so render is the meet of the widget this is where you're going to define your user interface this reacts to state changes so any renderable properties that you define will trigger a rerender and it will efficiently rerender any Dom that needs to be updated it uses JSX so you're working with virtual Dom which is nice so let's create a simple widget and this simple widget is just going to render based upon and enable the Belene property and that widget will be clickable so when you click it it's going to toggle enabled on or off and the display will change based on that enabled so this is what it's going to look like just a simple button up here it's either going to be disabled or enabled and clicking it will toggle its State cool so let's go into that so here's my simple widget right now if you look at the top right corner it just says hello world and clicking it does nothing let's look at a code for this so going into my simple widget view here I have my widget and I have my main and I have a list of steps to go through - cool so here's where I'm creating my map and map view and I'm importing the simple widget so I create my map I create my view I create my simple widget and I add it to the top right of the views user interface so pretty basic code I'm what I'm doing to instantiate this widget in my simple widget I'm importing the base widget class I'm importing some widget decorators and decorators for ESRI core accessor so this lets me define a property and declare a class so I'm creating my simple widget class and it's going to extend the base widget class it has a simple constructor it has no properties yet and it has a render method that just renders hello world inside a div so this is what we just saw on the demo I showed and I'm watching typescript for any changes and it'll recompile so the first thing we want to do is we want to test out the render method so let's add a class to this div instead of just saying hello world so now we have a class of simple widget still says hello world there let's see what that looks like I reload the page okay so now it's got this big button block look cool now let's improve it so we're gonna add a property to our widget and this is going to be our enabled property and so this property lets me to you know as a user be able to flip this to be enabled false or enable true and is renderable so any time it changes its going to call the render method again let's add some CSS to the my div as well so I've created this CSS map with a couple classes and I'm using the BM naming methodology so this is a block element modifier and it's just basically a way to name CSS classes to get good specificity on each class so my base class is going to be the simple widget and then when it's enabled it's going to have a modifier for enabled cool so we go back down to our render method and we're going to update that so now we're going to get a reference to whether it's enabled or not and then we're going to render a button instead of a div and we're going to add the base class and if it's enabled and enabled is true we're going to add this enabled class as well and then if it's enabled we're going to say enabled otherwise we're going to say it disabled cool so let's compile and test that so it's disabled right now and clicking it doesn't do anything but if I do simple widget I'm not sure a reference to it so let's skip that so let's add one click to this so we I don't clicked our button so that anytime this button is clicked we're gonna call the toggle private method so we need to add that and the private toggle method all its gonna do is flip the enabled status so if it's enabled it'll be disabled and if it's disables it'll be enabled just toggling the Belene value of this enabled property cool so now if I reload and I click disabled it becomes enabled and I click enabled it becomes disabled so it just toggles it so really like the simplest widget you can create but it kind of shows you how rentable properties work and how the V DOM is being updated cool that's our really really simple widget we've created and you can see we did it you know less than 70 lines of code so just to recap that we created a simple widget by extending ESRI widgets widget we implemented and modified the render method on the widget we added a renderable property and that just updated when the property change is changed then we added a on click event to the V Dome and that toggled the enabled property we used a CSS object with the BM naming methodology if you want to learn more about that it's get BM calm and it just tells you what it is and how to how to use it basically and then we toggle the property with the Kalon click and every render down so now I'm going to turn it back over to Franco and he's going to talk about how you can improve our widget this next section will be covering how we can improve our widget taking the concepts that we learned from building a simple widget and also reusing the logic that we created from the first class that matt showed how to build so before doing that I want to talk about the way we architect widgets in the JavaScript API and for each widget there is a view and a view model and we do it because we want to separate the DOM and business logic concerns we also want to make it easier to replace the UI if you need it to by keeping all the business logic in one side you are able to throw away the the view part and recreate one if you wanted to this makes it easier to integrate into other application frameworks because you have these two different pieces in separate modules and you can choose to bring in or not so for views just like we saw in the simple widget example end up extending the base widget class and rely heavily on the view model api's and just focus on UI and Dom aspect and view models on the other hand such as the items core class example extend accessor and they provide the API or data objects to support the view to support the view so that it knows how to render and this is where you would keep all the business logic such as fetching of data or manipulating objects into simpler structures that the view can take and render the way these two parts work is that the view will end up rendering the state of the view model either through its internal properties or by properties exposed on the view model then as the user starts interacting with the view it'll cause the view model or the view itself to update its internal state and that causes the view to we render again in update and this cycle happens many many times during the lifespan of a widget for this last demo we'll be creating the items core widget to give a face to the items core class that you created with Matt a few steps back before doing so let's just go over view some of the changes that we'll be making for the view model will be taking the items core class just renaming it so that we know that it is a view model and then we'll be adding a state property and this property is going to end up supporting the rendering of the view so that it knows when to render the idle loading or ready states therefore our widget itself we're just gonna expose two properties from the view model so as a portal and the item ID to keep it really simple for styling we'll be using the Cal side web framework which makes it really easy to style some of the parts that are used in my widget with CSS to summarize the changes that we'll be making we'll be updating the items core class and making it into a view model and then add a save property there we'll create the item score view and we'll be aliasing some view model properties creating a CSS class object using the BM methodology and then we'll be rendering different sections of the item so this demo builds upon the other demos that we've seen so there's a lot of similarities the index page is very similar to the ones you've seen before except that I'm now bringing in the Cal side web CSS style sheet in our main application I am just creating an item score widget which doesn't have anything right now and will be passing in item ID property and specifying the container for the div and exposing it into the window if we want to run some tests so we can start in our view model and I've gone ahead and already renamed it to item score view model to save a few steps and the next thing that we want to do is to add a state property like we saw on the slides so what this does is based on the status of the portal if it is loading the state of this is going to be loading and if we already have an item based on its loading status it's going to be either loading or ready and if we don't have a portal or item we're just gonna be idle we're not done with our view model and we can move on to the view so if I look into my view file I don't have anything except that I am extending the widget is class and set up my constructor with the item score properties that I'm expecting so let's start off by adding properties to our widget so I've added an item ID property which will be alias F of the view model and same thing for portal which will be alias stuff of the view model as well and we also define a view model property and we'll update the widget so that anytime any of these view model properties change it's going to schedule rendering automatically for us or first let's take care of these imports next up let's focus on rendering for the next step we'll be focusing on rendering and first off let's add our item loader and all I'm doing here for my main rendering method is to create a div with a bunch of CSS classes and I'm also rendering the item loader and the item loader is where I am able to provide the item ID and kick off the item loading I have some errors here because of the event handlers that I've not added so I'll bring those over for my input whenever I make changes to it as I'm typing it's going to call the handle simple value change and this event Heather is reusable because it's using a pattern where I define a property name that belongs to the view model I'm assigning it to an attribute on that input and then using it to assign that value to the view model so for example the data item prop a tribute for the input is item ID so whenever the input fires a change event it's going to update the view models item ID property whenever I hit the enter key on that input I've defined the handle input key down Handler and lessons for the enter key to be pressed and if so it's going to kick off the view models load method and in the same way for the button whenever it's clicked it's going to call the handle item load method and it's going to call the load method on the view model as well so similar to Matt's demo I'm using some convenience objects to store all my CSS classes and my text strings that I've gone ahead and defined in a resources file so this is where I have all my CSS classes and some are from Cal side web and anything that is text will be stored in this I 18 an object so let's go back to my rigid and import those objects now I can check out my demo so now I should be able to see my widget rendering and allow me to enter an item ID and this is loading the item I can turn our again so you can see so if I check out the view model state property through my widget you can see that it starts off as idle but once I provide an item ID and click load and check the state again it's ready so let's continue with our rendering next off we're going to be focusing on adding a loader and up next we'll be focusing on a progress bar to show as the item data is being fetched and I can do that right now by updating our render method in this version I will be storing the state of the view model and whenever that state is loading I'm going to display the progress bar otherwise I will show nothing and let's take a look at that progress bar rendering method and all that this is doing it's creating some divs and applying some CSS classes taken from Cal side web now if I reload and enter the item again we'll see a progress bar whenever I hit enter or whenever I click the yellow button now for this next step we'll be rendering the item score after the item is loaded and let's bring up our updated render method with this change in addition to checking for the loading State I'll also be checking for the ready state and wherever this is the case I'll be rendering the score for my render score method I'll be displaying the score as well as a score bar and if there are any suggestions on the view model we will be rendering the first one and what this does is it will be grabbing the first suggestion from the view model and if this is the case it's going to create a container for my suggestion and it's going to use the ITN object to grab the appropriate message based on the suggestions property and the type if there is no suggestion I'm not going to render anything I do have one error here because I have not defined get score color so I'll copy over the get score color method and all this is doing is based on a score it's going to return a different color so if I reload and load the item again I will now see the score reflected in the bar here that you see as well as the first suggestion to improve my item score before this next step will be rendering different properties from the item so let's go ahead and update our render method and what's so for now is that besides rendering the score I'm also going to be rendering this item form and what this is it's going to be a form that displays different properties from the item so it's going to display the title the summary description tags terms of use and a thumbnail for each one of these it's also going to allow us to update the value either by using an input text area let's continue by adding some variables that this form depends on and this is going to be used to display a preview for the thumbnail and let's add other event handlers so we need so most of the inputs are going to be using the simple value change that we saw earlier on but for tags it's going to be slightly different because we're working with space delimited values so we'll be splitting the value and using that to set the tags on the view model and for the thumbnail change since we're using an input of type file it's going to allow us to select a file and set that as the value for the view models thumbnail and we'll also prevent the forms native submit behavior that will prevent the page from reloading if I load the item again I'm now able to see different properties from the item but notice that thumbnail is just displaying in blank there's no image there so let's go ahead and fix that in order to do that let's add a method that will update the seminal blob URL that is being used by the image so let's go ahead and add that method and what this method does is that it allows us to take a blob and turn it into a blob URL that can be used inside of that image tag that we showed earlier next up let's actually use this method by leveraging some of the widgets lifecycle methods so whenever the widget is initialized and a thumbnail is set up on the view model it's going to update the blob URL for the thumbnail and whenever it's destroyed it's going to free that resource if I load my item again I should be able to see a thumbnail now awesome now if I try to update any of these input fields it's going to technically store them on the view model but there's no way to save it to the item so let's go take care of that we'll be updating the render item form method and adding a button that will allow us to save and this button will use inactive save variable to toggle it's disabled attribute on and off and we'll also be using an event handler when it's clicked to save the actual item data let's go ahead and add those so for the item save Handler all that it's doing is it is calling the save method on the view model and keeping a reference to the promise and it's going to store the promise so that the widget will render and update the button that we just saw and whenever the save promise is resolved it's going to clear the active save properly so let's go ahead and define that as well an active save it's just going to be a reference to a promise and similar to some nail blob URL it's also going to be renderable so when this property changes its going to re-render and with that we are done it was a widget and if we reload and check the item again we should now see a Save button here in the bottom left and now if I make changes and save we should see the score improve and now we get a different suggestion to improve our item if I make another save we'll see the score bump up and now the suggestion will focus on a different property which is description and I can keep making changes and we'll see the score move up and up and that is it that is our item score widget to recap we showed you how you compare a view in its view model and use a few model api's to render properties on the view we were able to wire up interactivity by using even handlers in the JSX and we were also able to apply styles with classes and we also saw how based on properties changing the UI automatically renders to recap the session we showed you how to set up your dev environment if you want to work with typescript and the JC API to create your own widgets we showed you how you can create a custom class and then showed you how you can use that class as a view model to power the items core widget here are a few additional resources and you can check out in the slides and I'll provide a link at the end of the presentation here are some other sessions that you can check out to learn more about getting started with the JC API typescript tips and tricks for development and debugging or if you want to learn a little bit more about customizing widgets if you have any questions such as work can you find the slides of course we have a bitly link bit dot l YF / built widgets the s20 will take you to a repository and hosts the slides as well as the demo code so you can check that out and if you have any questions you can submit them at the following link bit dot ly slash asks jsapi which will take you to GeoNet or you can post your question and with that we are done thank you so much for watching
Info
Channel: Esri Events
Views: 1,841
Rating: 5 out of 5
Keywords: Esri, ArcGIS, GIS, Esri Events, Geographic Information System
Id: XKmZLx56Jl0
Channel Id: undefined
Length: 50min 54sec (3054 seconds)
Published: Wed Apr 22 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.