Skeleton Loading in Service Portal: Part 4 (Live)
[Music] hello and welcome to code creative i'm travis Tolson getting an early start today with the code creativeLIVE I'm gonna be flipping back over to our skeleton loading again so for those who are just joining and haven't gone through the first three parts basically what we've been doing is we've been building a simple list widget that does this little skeleton well and login right that would help yeah let's try that again so when we reload we get that brief little skeleton load so instead of hitting the server requesting all the data and only rendering the page once all the data has been obtained we're rendering the page immediately and then asynchronously going back to the server in order to get the data and while that asynchronous call is dave Spangler and away we go logins are overrated they are they are if there were no logins there would be no security breaches that may not be how that works no okay anyway so you know basically we've we've created this custom widget and we've got a few things left on it to go first of all I have added a couple of instance options to it that last time we're not working properly notably this disable async and show skeleton so essentially I wanted to be able to through a couple of flags change it from asynchronous to an asynchronous and wait here in the chat mail - yeah you're in the chat and on the mic you're on my mic alright so I wanted to add some some options here that would allow us to flip between the default simplest behavior and it made ceases she can double smack you this way I can get shut down on chat and verbally all from the person right next to me so I can be hit from the front and behind it exactly at the same time oh gosh - true - true so yeah I ahead of these instance options so that I could get both the default simplest behavior and the asynchronous with the skeleton or without the skeleton all in the same and now that I think about it I may shift the show skeleton disabled async we might go to a choice list instead now that I think about it because that might more clearly communicate this one but either way that behavior wasn't working you can see that this one is supposed to have disabled async but when i refresh it still appears to show because I think this one's I've got the same way yeah see both of those are supposed to be disabled for the skeleton but it's showing so that instance option isn't working at all so that's the first thing I'm going to try and address the second thing is we have no link right now no hyperlink so we need to fix that and then the last thing that I wanted to fix about this list before I think we'll close it up and wrap up this particular chapter is the design staring at me yeah does it suck that bad so we're gonna take a George Carlin routine and we're gonna let let's liven it up a little so those are the three things that I'm hoping to address before we wrap it up and we'll see how far we get with that today all right so to start let's go ahead and reload this cuz it's probably stuck on the old session all right so the first thing that I want to do let's get rid of this old instance option sack let's get rid of now here let's create the new one first before I go getting rid of the old ones let's see I want to do a choice list instead and we'll call this one the load behavior Dave Spangler asks does that mean we get to rename it not so simplest now um yeah I guess we can the really complicated list let's see so load behavior choices so list version 2.1 dot I don't think I like you on the screen anymore well alright so choices are going to be will say synchronous asynchronous and asynchronous with skeleton not enough finals I don't know that's more your saying you're the one that actually lasted through college so I know I'm twisting it haha sorry okay Herman's sermons when the data for the widget loads and what is displayed while loading there we go we'll go with that yeah I feel halfway decent about that so then we'll get rid of the old ones disable a sync and show skeleton we'll get rid of those when you're doing your I imagine it's also helpful to actually have all the instance options configured as we were just dealing with an issue on a on a widget last night where the instance options existed over here in the script but they were not set up in the option schema and she had set up a widget using those options previously but couldn't remember how she did it I don't think I called you element I don't think a coach or nuts wasn't your widget it with somebody else's widget it was your own widget well you just called yourself back then totally somebody else all right so let's see here all right so with the changed with the change to those options we got to update our normalize function and what did I call that option let me copy this over to my text pad and you guys can't see this cuz it goes off screen but on another monitor I have I almost always have some text edit or open and I just kind of copy stuff off to it it's like my extended clipboard which again there's probably a better tool for that but yeah and I actually have to move it because it's in the way of the chat so I can't see what everybody's saying I think I need a third monitor let's see oh dad jokes John how's it going we're gonna change this to the load behavior options da load behavior will get rid of disable async and that should fix that next up I've got to calm down here and so basically if we are if it's asynchronous passing input or if our load behavior is synchronous then I want to go ahead and execute this and pull in my list items synchronously or during this script because if it's asynchronous or if the load behavior synchronous that should load the items and then we also have to come over here and if the options load behavior is not equal to synchronous then I'm going to assume that it's one of the async ones confusing use of oh I had a double knot so let's fix that thank you complain about my puns only because I appreciate puns in you go oh my goodness let's see so the load behavior is synchronous data is loading now here's the other piece if we are loading and the load behavior is a sync with skeleton and we're gonna save that we're gonna see what happens and hope nothing breaks okay we've got the preview that looked decent I think did it load thee it did not load the skeleton oh wait let's check our actually let's do this let's come up here and let's add our default option so load behavior or default is going to be a sync with skeleton whoo that look good okay good good response from the simplest if you watch the preview there when I save the skeleton shows up it loads asynchronously that is behaving how we want it to now let's come over here and let's check our instance options and configure a few things here you have the preview window open okay yeah so basically if you come over and for in case anybody didn't hear Sarah she was asking that on some widgets there she's not able to bring up the preview window in the editor here and she was wondering how to do that basically if you come here to the hamburger menu you'll see and enable preview checkbox yes that's that's what you're missing some of them have it checked by default some of them don't and then that may I can't remember if that's a user property or a property per widget I can't remember exactly how that is but that's what you need to check is make sure that that checkbox is tagged in order to get that to pop up that's it okay yeah sorry dumb question now in case anybody missed what I was looking at before I completely borked something with my instance options because synchronous asynchronous and asynchronous with skeleton is not supposed to be an option that's supposed to be three independent options so let's check the option schema and look at our choices ah one line per choice following directions was never my strong fun of my strong suits just asked the United States Marine Corps okay think that worked let's try this again [Music] instance options there we go okay so before I do anything let's check okay everything loads with skeleton by design that's our default option now I'm gonna set these two to synchronous oh it's looking good it's looking good this one to synchronous oh yeah I'm loving this instance options will set these two to asynchronous this one to asynchronous so these these two should be without the skeleton and you notice that when it loads it's just blank and then the last ones I don't have to set it but I will asynchronous with skeleton and I'm actually gonna take this one step further because in all reality even though I don't trust the default options in here even though ah come back wait stop no go back I don't even know pacing with skeleton default values short description for that one let's save it alright so now we should be all set and if I reload there we go this column is immediately available on page load this one this column here loads shortly thereafter but does not show a skeleton and the final one you'll notice shows the skeleton now why all the complexity well it depends let's go ahead and clear my cache real quick and let's see what a fresh load does and see if it impacts in this case it may be so fast that it doesn't it may have no impact for this particular which we'll find out that actually loaded faster everything loaded faster alright interesting so I actually expected that the that the no skeleton synchronous load I expected it to run a little bit slower or wait a second that's generated and okay let's go with it's not there a way to check the page load time aside from my performance console I thought there was something in service portal itself I know there is in the native UI but I thought service portal had a - I thought it had something done da-da-da-da-da-da but I like my musical interludes alright let's just do a reload well first first let's do this let's set all of my instance options - and I'll shrink this up a bit as well so I can quickly flip instance options waiting waiting waiting waiting waiting waiting waiting whole lot of waiting there we go alright so I'm gonna set this to a sync with skeleton I'll set the other one to a sync with skeleton basically what I want to do right now is and this is just out of sheer curiosity I am interested to see how long the page takes to load with all of them asynchronous versus all of them synchronous I just want to see if it has an impact so let's see let's reload now what I don't know is if there's a page load that I have to include in this tourist phone awesome SP patch SP bootstrap app I think I can just go off of this one maybe I have no idea I don't know let's clear that wait a second load one second alright so here we go let's see Dom content loaded 375 milliseconds load 398 milliseconds so 500 well round up 500 rounding out 500 so it looks like we can pretty consistently hit at 500 milliseconds the finish is at 1 second so we're sitting around half a second to one second half a second onload one second to finish for the whole page so now let me go through the instance options and set all of them to synchronous and let's see if there's an impact at all on this I'm suspecting that there should be some impact I don't know if it's going to be huge because these these queries are fairly efficient compare this to some of the queries that I've seen in production instances where there's a lot of a lot of nested queries and stuff like that or slow ACLs and this stuff can get a little more hairy this is especially true in customer service management where there's a lot of account checking and there's there's a lot in terms of query modification and such that goes on in the background of any portal I've ever developed it's only been my CSM portals that have flopped over and died performance-wise and required indexes to be added and all kinds of craziness and it's not a knock against the CSM application mind you it's just a nature of how that applications developed by design it has more checks and balances in it alright so let's see first load 800 milliseconds and 117 to finish second load we got down to 500 and attacked that's actually the fastest finish we've had for four synchronous load 400 so this is interesting right now it actually seems to be performing better with all synchronous which is really interesting and I would not have expected to see them let's flip it back to and of course you know with network it's it's hard to tell exactly it's it's hard to nail it down because at any given moment in time especially with the live string going you know is something happening in the network packets is something happening on the network has a bunch of people come home and started watching Netflix I have no idea now all the kids are home from school turn kids in their Netflix so it's it's challenging to pin it down exactly but I am I will say that I am surprised I expected the asynchronous with skeleton to have a faster initial page load but to potentially take longer to finish the overall load to flip into async across the board just to rerun some of these and one more alright so clear out reload 800 on initial 1.45 to finish and then we're immediately back down to our half a second to a second so yeah it's you and that's the lowest finished we've had for a sync so overall it looks like the two methods are actually in roughly the same ballpark with synchronous actually being a little bit faster on these on these really efficient queries you know and this goes back to what I was saying in one of the first videos where you've really got to test your different scenarios you've really got to test this with your user base to see which they prefer you know you may find that one provides a better user experience despite the fact that it actually loads faster you know perceived load is a very important concept in user experience so you know if you really got to to pay close attention to the details on it and you know the other part of this is like I said before if you're I'm HD says I don't have caching disabled in my dev tools oh my goodness outstanding catch timings might be more accurate yeah you're right so what he was saying was that the this disable cache was not enabled so essentially anytime I reload the page it could be hitting my client-side cache and therefore completely skewing the performance numbers so let's just give a quick check oh we're a lot slower now we're a lot slower now because we disabled the cache so now it's actually so basically there's multiple of cash when you request a page Sara asked why is it so much slower now and basically there are multiple levels of cash whenever you're dealing with web content you can have the browser cache which is literally on your machine it is on your computer if there's a successful cache hit on your computer than whether it's an image a web page basically the your browser doesn't have to hit the server for that content at all it retrieved it from the local cache there's also server uh you know CD ends are a form of cache and then you have server-side caching so even though I cleared my server-side cache with the cache do I did not have my browser cache disabled and so it could have been skewing the timing so yes at this time we've got a load of two seconds finished in well that can't be right Wow not that kind of cash [Music] all right so finish in two and 1/4 seconds load in 1.75 1.78 2.25 so it looks like one and a quarter two and a quarter is what we're getting off of this one let's see what we get when we go straight synchronous again surprised she didn't ask if you were talking about Johnny Cash crash you know see it it's on it came through through tweet tweet what are you on YouTube oh you don't have mine my master stream ha ha ha my secret tools that you know the smarter dead folks told me about nice yeah I could not be doing this whole live stream thing without lots and lots of help from the dev MVP guys they were giving me all kinds of info and and the developer advocates to Barnes you know all of them were where we're getting all kinds of info on how to get started with this stuff what to use so helpful alright so we got all of it set the synchronous now let's do our reloads ok so that was absolutely atrocious this time the load was four seconds the finish was four point three hopefully it's a little bit faster a couple more times there we go so now we're getting now we're getting much closer to what I expected ok kevin eldridge okay that's crash I keep forgetting whose username is which which person and I can't just like hover over to get their name well that's because all of them went by their screen name that's true too second load 2.48 ok perfect mhz thank you so much for pointing out the disabled cache with the cash with the browser cache disabled I'm now getting much closer to what I expected to see so now with all of these set at synchronous you can see that this page is now taking whereas with the async it was taking 1 and 1/4 seconds to initial load it's now at 2 and 1/4 seconds to initial load and I want to say it was like 1.75 or something like that for the final render and now we're up in the 2.8 second range so you know this is much closer to what I expected to see and this is where if you have you can imagine if you had more complex queries slower queries on any of these simple lists or even on the main content itself you know some of the forums for example have multiple queries that have to be performed in order to render that content that plus a handful of synchronous simple lists and you could dramatically slow down your portal page and since you know from user experience tests we know that you know from the commercial side of things you know the b2c community we know that there's a lot of money on the table per second of load time you know people are accustomed to very quick web pages very quick loading and they are very quick to abandon self-service when your web page runs slow and this is one of the few drawbacks that I'll point out on service portal is that it is fairly heavy weight in terms of a front-end content management system that is why I look for tutorials on how to use service directives to house that data yes MHz points out that he uses service directives to house that has this data that will be shared amongst widgets and this is something that I extensively in my own widgets in fact and one of my knowledge presentations I discussed inter widget communication and highlighted that angular services are my preferred way of handling inter widget communication and sharing data basically for the react folks out there an angular service can function and can be treated in the same way as a react redux store you know so you can get approximate to the the the the single direction flow in your UI by using that it's not true single Direction flow because you know angular with ng model especially still uses two-way bindings there's ways of dealing with that as well if you want to keep things sensible but it is a little more complicated than systems that use true single direction flow but that's going down a down a technical rabbit hole yeah making service portal widgets work together was the name of the session and I discussed the the angular services in that session these angular services are really great I actually started working on kind of a master angular service once upon a time that would essentially allow you to create a glide record like query in the client script and it would cache the results behind the scenes in order to share that data amongst widgets and so basically you could write glide record style queries in your client script and have no real understanding of the underlying implementation of how it was being retrieved you could bypass the server script altogether I got close to something functional on it but I never quite finished it in part because the whole UX framework conversation started coming out and I was like I'm wasting all this time on this dag on service and oh cool thank you so Sara dropped the link for the for the inner widget communication session in the chat if you're on Twitch I think she's in the youtube and put it in YouTube so you guys may not be able to see it alright so but yeah so basically this is much closer to the results I was expecting you know the the load time does take longer you know we're III would honestly say significantly longer because I mean you're talking to jump from what was it 1 1.75 or something like that 1.25 initial load to up to 2.5 on this one so that time it loaded faster that time we got it down to one point seven eight you know but you can see that that loading this stuff synchronously does take more time to initial load and if you're thinking about stuff like a knowledge page a knowledgebase article you know load the article synchronously absolutely there's no point in rendering a blank page just to go back and fetch the primary article you're showing but if you have a bunch of related lists off to the side showing you know related article content maybe consider loading that asynchronously so that those queries aren't holding up the overall page look yeah MHz says you have to watch if you're on Wi-Fi which I am not only on Wi-Fi I'm also on Wi-Fi through a couple of walls doors and probably a few small children's heads but but I am on Wi-Fi and you know the instability of life I can absolutely skew the numbers the fact that I'm streaming could skew the numbers I mean there's so many variables on the network that could potentially skew the numbers but just from a logical perspective you can estimate that at least some of the time even if it's only the first time that a user goes to your service portal you can anticipate that certain caches are going to be missed because they haven't populated those caches and you can anticipate that the synchronous load will take at least a little bit more time than an async load you know and by strategically choosing when to use synchronous versus asynchronous you can get a better result in your portal you know and that's why I said I've said in the past few parts to this I highly recommend using synchronous loading on the primary content for the page the primary reason you're loading that page and then your secondary supporting ancillary content you know for that stuff you is when you want to use the asynchronous load you know you can load that after you've presented the user with what they're actually they're looking for all right so let's keep on coding and I'll jump off my soapbox in my over analysis of microseconds of page load time it won't hurt the kids heads it's fine it's all good all right so let's see what did we have next what did I want to thank well next I got that working I got my options working I don't want to do that there was something else in between yeah I know this is the beauty of coming completely unprepared let's see there's meta fields it's kind of thinking about ditching the meta fields for now maybe dealing with that some time when I actually need it and feel like going through the pain of it unless somebody really wants me to do the meta fields and populate meta fields I'm happy to skip that I'll leave it just in case in the next few seconds when will huh you got like 10 minutes where you going your attention will be divided you're gonna be abused by a small child her youngest is Rafael if you don't mind all right well crash says he wouldn't he that he would like to see the meta field so sure let's go for it let's see okay so basically the meta fields in my mind what I was looking to go with here yes parents abuse Jace parents abuse and I know you know that's a thing I didn't want that page just ESP page parent Protective Services in that like grandparents I think frame grandparents or parents let's see alright so for the meta for the meta data this this is kind of what I'm thinking of for the meta this is just like the you know you can stick tags down there or whatever I don't know that's that's what I'm referring to as the as the meta information you know and on some simple lists you'll see it shuffled off to the right hand side I've seen some where you it has like a little info pop over he and I both know that very well from his kids to my kids well parrot abuse how are you in the twitch now alright so meta fields for meta fields what I want is a comma-separated list um so let's do this we're going to and this is no no no no no no no no I'm not gonna do it I do need to convert my comma-separated list into an array and I'm not going to do it here I'm not gonna be that guy I was tempted to do this to kind of shorthand in line the whole thing and do split , you know and split it that way but I'm not going to be that guy I'm going to separate it out I'm going to keep my my responsibilities separated here let's see get list items it is loading items alright so I need to change my get list items here alright so here's what we're gonna do I'm gonna create a new function yeah so I want to now I don't really want to let's see if I can get away with it let's see what we can get away with alright so for our meta I don't need a field name well ok I see what I was going for here I've got an array of fields an array of fields and each one is returning something all right we're gonna create it we're gonna create this function and we'll call it get get field view object field and I will pass a glide record and a field to this function yeah we do we do not both have a multi-monitor setup Sara works on the couch I used to work on the couch too but when I started doing the streaming thing it got kind of weird pulling out a monitor and setting it randomly on the coffee table so I decided to end my back started killing me from sitting on the couch hunched over a computer all day so I've been playing around with a new desk setup yeah my whole office is constantly changing alright so for this function I am going to pass in a glide record and return a field and what we're gonna do is return an object and we're gonna we're gonna say value 0 dot get value and we need ops as well apparently you or actually no I don't need opps for that cuz that's gonna be the field name so field name get value field name display underscore value er dot get display value field name and finally we will give the field name and we'll just pass the field name straight through so basically what I'm doing here is I'm creating a quick function and as I said in the last one I don't have to do I don't have to pass this function name as a parameter I don't know I don't actually know let's not do it that way I feel like that's ugly what we're gonna do is I'm going to instead put this as a dependency now cuz that means that's gonna get called every time that calls yeah I think I can live with that now we're gonna yeah I'm gonna pass this in as a dependency I'm just gonna be explicit about it rather than using closures and what-have-you I'm just gonna pass it in so that my dependencies are explicit this function knows that it requires that function and what we're gonna do is start item item title field and now I can get rid of this and then I can do the same thing for the description field and I can get rid of that okay all right so the whole reason I built this function was for building out the meta because I have an array I have to be able to I have to be able to pass these these values over and over and over again I have to pass each field in and generate this type of object and I wanted to simplify the function that I was going to be dealing with in here so generating the meta I have to I have to get my metafiles so stop meta fields dot for each will iterate pass the field name and what happened don't make functions within a loop ah yeah I know I know I know don't make functions in a loop but what about just this one time let's see how can we go about this all right we're gonna strip this stuff out I'm just gonna include it inside and we'll include the whole set inside as a closure functions in a loop are quote unquote bad from the perspective of performance basically each time that loop is executed the function has to be recreated at least that's my understanding of it and I'm sure a lot of that probably depends on the JavaScript engine the JavaScript interpreter itself and how it handles it so what we're gonna do is I'm gonna go back to what I was originally considering which is internal functions uh not what I wanted yeah exactly Jase it's just like read Eclair in a variable and I'd have to assume that a that a smart enough interpreter would be able to figure that out would be able to figure out that here's a function declaration within a Loup don't do it but I don't know cuz I've never honestly tried to write something like that before so I don't know if that's sensible or not what about the baby has drilled into the room yes yes the youngest has joins probably not really cute black blob black that black dot blot and dave Spangler so same concept but theoretically can have a bigger impact not that I've seen it caused any major problems yet good to know Dave thanks for sharing that III haven't seen it caused any significant issues myself I mean honestly in most cases we try to keep the iterations to somewhere around the range of about twenty a hundred at most anyway so a lot of when it comes to these these performance issues in JavaScript I can guarantee you that any day of the week the performance of your glide record query is going to be far worse than including a function inside that loop every time guaranteed without fail I simply simply making the query is going to take more more time in terms of performance than basically the entire rest of your function in most cases J says it's not a problem if I can't see it exactly if it and that's my thing is and I know a lot of I know there are some folks that get hung up on you know really really my new performance details I attend not - if it's not impacting my users if I can't see a blip on the Ray and then it's not a problem oh yeah J Jase G our calls are terrible yes I agree especially when you start nesting them or the hidden nested ones oh gosh and some of the some of the portal widgets that exist have nested glide record queries built into them you don't see it when you read the code but if you dive in and pick it apart there are nested glide record calls in them especially for your tree view type things like the knowledge base category picker or the category drill down and I don't know if that's still a prominent one that that's used in the default portal or not but I know that one had a lot of issues for a while with large catalogs I mean it would flat-out destroy performance on the knowledgebase home having type 1 on Travis's keyboard that wouldn't be too distracted oh wow James Neal joined in 10:30 p.m. his time thanks for joining and welcome welcome he's UK oh I'll bet you he has the accent Sarah trashes me all the time because i i i i have a whole british line in my family but you know american born i have no accent and so she ridicules me all the time because i didn't get the accent again with the calling me out man James says I do well clearly we're gonna have to get him a mic on the stream sometime [Laughter] let's see I don't even remember where I was let's see get feel okay right we were iterating the meta object or the the meta fields so what I needed was to move that function out I'm gonna call this one each meta field really okay you should I be doing it differently you work well he's he's talking to me he helped me he helped me beat you guys ago fish last night ah let's see each meta field we're gonna pass the field name it's what I wanted to pass and then what we wanted to do was call get list items and I'm actually gonna end up changing that to a map and we'll say with her not get list items we wanted let's give a little visual separation there get field view object is what I really wanted and we're gonna pass kind of hoping this works I think that might work but I'm not sure we'll find out we'll see how it goes gr field name and then we're gonna change this to Matt and for those that don't do a lot of array manipulation what map is gonna do is it's going to loop it's basically a for each that loops through each of our meta fields it's going to pass that meta field to the function and it will take the return object from the function which in our case is going to be our get field view object and it'll basically create an array with that new up with that returned object so to give you an example if I were to do something like this return item plus one then the result would be an array that was two three four or five six right so JJ's points out really mattress gives back a new Iraq and right it's gonna turn around and it's going to take this array it's gonna pass each item in and then it's going to create a new array with the result of this function applied to each item as it goes up so map and we'll say each Mehta field was the name of our function so each meta field gets passed to this one which calls our get field view objects which should return our result gotta get rid of that okay where we at where we at where we at options fields okay so in this case I should get my assigned to and now I need a place to shove it I need to put this in the view somewhere so I've got title description here's what I did alright so we're gonna take this div and I'm gonna create a series of spans using ng repeat which ng repeat is basically a for loop in angularjs terms and we're going to say for each meta in what's it gonna be item dot meta I kind of don't like that name let's say meta fields that feels a little bit better at least for each meta field let's say for each field in meta fields and then we'll throw field dot display value and I don't know if this is gonna work or not to be honest yeah that didn't go well cannot find function get value in object number line number 25 so if I hit 25 cannot find okay so basically what's happening here is pretty much what I was concerned about which is when we called map we passed the field name to each meta field but gr doesn't get packed so gr is undefined in here maybe is saying meta meta meta where'd you go alright so gr at this point is undefined so I'm gonna use a really really quick trick to fix this I'm going to return a new function so we're going to create a closure here and what I'm gonna do is I'm gonna pass gr in to the into the first function which is going to return my actual iterator function check how the preview is pulsing while you review the errors I'm not gonna lie it was a little bit distracting I almost closed the preview because I was having a little bit of trouble reading the errors with the pulsing in the background it's a great animation not for a background to Arizona so then what we have to do is we got to come down here and we'll Pat what I'm sorry what he's talking to his blocks well fine be that way talk to your blocks hmm Travis is bringing back blink really that's where you're going with this all right so let's save that no dice um all right each meta field pass gr how I see what the issue is I [Music] forgot to include gr in these as well so I updated the interface to the get field view object function I updated the inputs but I did not update my function calls down here so those were returning undefined as well simple blinky list hey our error has moved to Lane 53 cannot find function map an object assigned to ah so this is where I said before that I wasn't going to do this up above split comma then map so first we have to take our comma separated string split it into an array and then map over that array and apply and one more time with feeling there we go now we've got an assigned to that has been added to it and if I add sis created on just as an example we get that one added as well now one of the things that I would definitely want to enhance this one with is the ability to format those dates a little bit better baby was like if you do that it's just gonna push your ear to line 53 he's trying to coach me back there but I'm a slow learner so you didn't have to pack me up on that I thought the arrow um alright so we're going to go let's see what else is there let's go with priority so I don't have to deal with dates right now and that's the only reason is because I don't want to deal with dates right now now I think on their side they put like a little dot yeah they put a little dot I'm they only got to put the dot in yeah can we make one oh oh you mean the style of okay I see what you're saying yes you're saying that it's annoying Sarah now so we'll fix it what's the I think it's text muted is the bootstrap class BAM okay now we need some space and to do this you can padding so you could do like a padding right but if you want to add a dot only if they're only in between items um then you have to know when you're at the last item so I want to say that ng-repeat has okay so yeah ng-repeat has a few different offsets here index first middle last even and odd and these are little boolean helpers that were turned true or false so I can put an NG if I can put an NG if last and it will or if not last and it'll do it on everything but the last one okay kind of like the CSS selectors yes yes yes exactly like the CSS selectors for first and last I like to do foobar split map string trim so whitespace is never an issue ie Glide list display values oh good call James Neal yeah so what James was just saying in chat was that what he likes to do is he likes to put in a string trim yeah James would be an authority on whitespace issues weight space studios to get up that's awesome that's awesome but so he was he was saying that he likes to turn around and do a string dot trim so that we don't have any extra space any any leading or trailing spaces on our results what I'm gonna do is I think I'm gonna stick that over in our where is that function see this is why I did not want to do the inner functions because it gets harder for me to see the inner functions and is that just a string dot trim is that how I use it is just it was I can't remember if that's a that's an instance or a yeah I can just do okay so I can just tack trim to the end of it so we'll do trim and trim I think that'll work maybe alright so that should work ideally in most cases I'll have to go back to my article on what the results were on the return values for the get values get display values and all that because I can't remember off the top of my head let's have the reason I write this stuff down all right so then all right so we got our meta fields oh right I was doing the ng-repeat so what I want to do is I want to say span and we'll do an NG if not last I think this should work we'll just start with a dash for now and there we go you can see that it inserted a dash in between but it didn't tack it at the end so that's how we can turn around and use that's how we can turn around and use the the the dollar sign last and I forget what that they called it special property the dollar sign last special property of of the ng-repeat directive and I have to say that now that I'm looking at that special property seems like they were just running out of terms when they came across this one directive services you know they've got all these complex fancy terms and then they come up with special properties for this one I feel like they might might have that went in is there any particular reason to use the angular last first whatever versus just handling at in CSS not that I can think of Sarah asked if there was a reason to use the angular versus the CSS and not really that I can think of the one advantage I can see to the CSS is that quite obviously if you ditch angular then that no longer has any meaning whatsoever whereas if you're using CSS to do it then you can you can apply that same CSS to a different frameworks rendered HTML and it still works that's the only advantage that I can see it using CSS unless somebody else has any thoughts on that oh and I just saw James Neil says just beware that a get value field will return null if the field is empty James that is exactly what I was trying to remember that I couldn't remember from my analysis on it sue normally I'm reluctant to do this sort of thing but I'm gonna its future Travis's problem future whoever decides that they want to use this thing it's your problem [Laughter] actually now that I think about it plus quote quote might only return the string null that might be bad I can't remember I did but that requires going back and reading my content and who wants to read Mike [Laughter] I'll go back I'll go back and I'll read that one later cuz that'll take me a while to figure out my thoughts behind it unless James has the answer if James already has the answer and is already familiar with it then we're set to go I figure worst case scenario here wait wait wait wait wait wait wait wait got it got it got it got it we can just do or or quote quote and that way yes article I'm too lazy to read I should just be able to do or because if it comes back as a null empty string or undefined any of those should be false and give me the empty string so we're gonna try that and hopefully that works and doesn't break now just because I want to keep some continuity frankly I honestly kind of liked their little dot approach and yeah don't stop go back I didn't want to click I wanted to inspect element on it so that I could hijack the dot give me ducked small I don't this is where are you aha the dot copy that and we'll paste that in here there we go James says it will print null doing plus quote quote thank you James man I'm gonna just step down and let you take over the live stream we may be better off yes or you can have yes I'm just here for community purposes just comedic purposes all right so that's that's not shabby she's got too shabby it's not great it's not great well nobody asked for your opinion man everybody's a critic he's mouthy he is Mellie bla bla bla bla bla bla bla alright so so that's how I would go about setting up the meta fields really what it all comes down to is you're gonna pass in a an array of a cop or sorry a comma-separated string of the internal field names you know in this case I'm gonna stick to ya actually now go back I'll keep it what I had it before and we'll continue to iterate and play with that but you're gonna pass this comma-separated string of field names you have to convert that that into an array iterate the array and process that into your view object excuse me are we good back there you're good new are you sure do you need to come up here roll your face against my keyboard [Laughter] alright so that's basically what we have to do in order to process the meta fields after that and I'm gonna start looking to wrapping this up so maybe next time we'll worry about the CSS saying and the prettifying you can't plan you got to shoot from the hip dude that's a few hours in it of itself alright so the next thing I want to do before we wrap up for too des is I want to add our anchor tag now we do need an NH raff but I think I'm going to go with an ng-click on this one as opposed to the href one of the things that I like first of all something you have to keep in mind about angularjs is that this here is called an HTML template for a reason it's not the actual rendered HTML so when I specify an anchor tag here that's not actually an anchor tag that is an anchor directive that is built into angularjs --is parsing and digest loop engines and basically angularjs is going to take this directive and process it into something else now I like to use the ng click over the href because the href forces you to provide a very specific URL the ng click and I suppose I could do an NG href as well to attain a similar result but what I like to do is I like to say click click item or something along those lines equal to function pass the item and what I like about this approach is that now I can introduce logic into my click you know what inevitably happens is your list starts out very simple all you need to do is direct to a URL but as you start adding whether it's instance options or additional logic eventually that simple href suddenly starts transforming into a more complicated set of logic to determine which URL to route to so I like to create a routing function in order to handle that for me in order to do that we do need to inject the dollar sign location dependency this is an angularjs dependency and basically what we can do is we can do location search what locations search does is it's going to update basically everything after the question mark I think in URL terms that's that's called the search parameters or something like that don't quite remember off the top of my head but that's more or less what it's referring to so basically I can say ID form table I don't know and I think it's this ID is the next one so these are the URL parameters that are required for our to in order to load up our form view so what we can do is I can inject this and pass my item from the ng-repeat okay and here's where I have to do a little bit of thinking my table are we okay okay are you sure all right pops4 c dot theta dot opt dot table that's the table we're querying from so that's the form link we want to go to and then hmm we need to extend this a bit because I do need the items sis ID fortunately we've got a nice easy function here so I can just copy that guy paste it not a period and what we can do is replace that with society and that should allow us to do item not society dot value now if I load it okay so now we've got our link baby said query parameters then felt a little jilted when you finally said URL parameters poor little baby nobody understands him yeah so basically it doesn't make the link for you I the the dollar sign location service will generate the URL internally yes and it will route to that URL so for example if I save this you know again keep in mind the the ID is the page ID is for it we're going to the form page the table is whatever table we have in our instance options which for most of them is going to be incident and then the ID should be the idea of the record we're gonna get to them we're gonna get to Zion and we're gonna get to that so for example if I click on this one now it's gonna go to ID form table incidents this ID and there's our ID and there you go it pull it pulls up the form page okay so next up we can add some instance options and this is what you are talking about sarah is first of all we can decide which page we go to but the other thing is that because we've we've got in here we can easily specify our URL parameters in this function as well so for example I can turn around and let's edit option schema and let's add target page and believe so I'd have to look up which which parameter controls now this is one potential disadvantage of the ng click is I don't think or does it yeah so the one thing I don't like about the the click approach is that they are or the ng click is that when you right click you break the open the right click open new link you break that behavior and this is one of those things where in most cases if you do open in new tab you want to provide some visual indicator that clearly identifies that you are launching to a new tab or launching to a new window because most user experience expectations are that it's going to open up in the current window and if I want it to open in a new tab I should right click so that is one disadvantage and I may play with that one a little bit to see if I can't keep the href but do it in a slightly different way we'll see how that one goes and there may also be something out there that allows me to control that control that right click with the ng click I'm not sure let's see but we want to determine which page it goes to and this is going to be behavior all right Jase Jase is dipping out thanks for uh thanks for joining man appreciate having you here always have a good time hanging out with you and the default value here is going to be formed well yeah I don't know I don't know I don't know I don't know I'm gonna keep this one simple for now I'm gonna keep it as a simple string I may work to improve the user experience later but we'll call this one the forum page and I'll update this to ID in order to reflect target page ID okay and then we need to update our options target page ID options dot target page ID and then what we can do is I can come over here and I can say C dot theta dot dot dot dot target page IV so now through instance options I can change what URL that goes to now with some additional effort we can also update let's go ahead and do this I can also update the URL parameters themselves in order to do that though I have to extract it out because what we end up having to do is I would have to say params James Neil says I got a type though good call yep thanks man good looking out so for the params basically what we can do is I can turn around and let's say that let's say that I had a Oh MHz had called out the typo sorry about that well both of you could call so for the params I can turn around and you know this is something Sara was bringing up earlier which is that you know the forms page may require table and society but not all pages require those same parameters some pages call it society some just call it ID some pages call it something else entirely you know KB article or something like that so in order to specify the right criteria we may end up having to create instance options where we can configure what the item ID gets in what a URL parameter the item ID gets injected into and what URL parameter the table ID gets injected into and to do that you know we could turn around and we could say something like C dot data dot ops dot [Music] sis ID URL parameter for example if I created that would have been insidious it would have always worked until someone passed a different since option variables or instance option value oh yeah aren't those the best the best errors to troubleshoot the ones that work but not the way they're supposed to hours and hours and hours lot entire lives have been lost and sacrificed on the altar of those kinds of errors all right but yeah so you know with this we could turn around and we could set that parameter to item dot sis ID dot value for example and let's do the same thing with table and I'm actually just gonna go ahead and create it I mean we're halfway there already and then we'll wrap it up item so with sis ID and it was table URL parameter so then I'll remove these two or actually wait a second we need C dot data table okay so now I can remove these two and pass params to the third okay I'm feeling pretty confident about that then we'll come over here and we'll say actually this lady URL let's keep our our naming conventions consistent table URL parameter so that one is going to be options dot parameter or what was it sis ID OD and then we'll have table URL parameter options dot table URL parameter or and I'll say oh no no my bad just table yeah tables well what it was okay so that's all set up last step is to edit our option schema and add sis ID URL parameter and default value will be sis ID and that's gonna be behavior whoops I forgot the other one and our last one is going to be table URL parameter string behavior default value is table and that should round that up okay so now if we reload here open up this one it goes to form let's change this one to go to the ticket page and so now this one's going to go to the ticket page and if we were going to a page where we had to change our table and society parameters now we can easily adapt those parameters to point it to the new page without having to go in and edit the code we can use the exact same widget across the board so with that I think we're gonna go ahead and wrap up for today I think that gets me to where I wanted to be I've got our anchor tag in there I've got our URL it clicks we've got the meta we've got the synchronous asynchronous and asynchronous with skeleton all working properly and next time we'll dive into styles and making some optional styles for this and that should wrap up this widget in this chapter and then I've got some other ideas for the future so I'm going to go ahead and wrap up this one for today thanks everybody for joining I hope you enjoyed it hope you found it educational helpful interesting or something that is somewhere relevant - worth your time thanks a lot guys and I hope you have a good one
https://www.youtube.com/watch?v=SCd0eDalbXI