 Gweithio i'r cymweithi ac yw Gweithio Cymddsodd neu Oes Yn Ni. Felly hynny wedi gweld i'r cynomad. Mae gyllid i'n gweithio am gwaith Cynlliannau o'r pellau o'r Merthyn. Felly e'r gwaith Cynlliannau Cynlliannau Cymru. Felly e'n gwneud i weld y cyfwelfigau yma, bob dyna gwneud i'r cywelfigau yma yn y gweithfyrwyr, i f Familie Hwnnw, fason i'r cymwyffi, y gallwn gydweithio mewn mwywg am Ymba Lywodrach. A dyma ym 1.3 ym 1.3? Mae ym 1.3 rydyn ni gael Aelod yr Aelod, ond mae hwn yn gŵr. Mae llawer rydych yn y ddefnydd yma'r fath arall. A bod nhw'n ddym ni'n gweithio lei, ac mae'n ddiddifwydd Cynary – fe yna bod ydych chi'n ddiddog yma – rydyn ni'n argylchedd yn ymyfyd. Felly, mae'n meddwl ydych chi'n gweithio llwy fath yma. I'm going to kind of go over that, so I think that when you're trying to solve a problem it's easy to just think you need query params, why do you actually need them well because you're a web developer and you're used to using query params and stuff, so I think it's good to actually be explicit about the problem that you want to solve and about the pain that you're trying to solve, so there's got to be like a reason to do it rather than just query params being a problem. That's something that you're used to. So what is that reason? So there's in Ember that you can deal with lots of application states, I mean in essence the core of Ember is arguably the router and the router is a big state machine and it used to be clearer that it was a big state machine but it's kind of being hidden a bit behind the DSL but at core the router is the broker between your application state and the rest of the world. So this is an application you might have seen called Ember Beats, actually it's a nice drum machine, you can make loads of nice drum beats and play with it. It's really fun, you should go and play with it, go google it and have a go but the thing I'm trying to illustrate is that you can store a hell of a lot in the URL using normal root segments. So this looks like a base64 encoded string which contains the whole song, it's probably just some kind of JSON structure that's been encoded with a base64 so you don't have to just store a numerical textual ID there, you can have a massive amount of state in your URL so you think that you actually don't really query params because you could just serialize a JSON object that represented loads of things rather than just an ID. So that kind of breaks down if it's optional so if you wanted to sort a list for example you're going to need to have two roots and one of them which has params and one which doesn't and this syntax is actually wrong, you'd have to name them separately and they'd have different names, you'd probably have to do something horrible with subclassing roots, it just wouldn't be very nice. Also, what if it's controller state? So if you just want to store something that's the way a controller displays something, a controller is something that presents a model to a view and something like sorting isn't really model state, sorting is more about how you're viewing it than how it's stored, how the data structure is created. So there have been obviously some attempts to solve these problems, one of which is my own Ember query which solved quite a lot of problems quite well but it was horribly buggy, it was really hard to keep up to date with changes in Ember because it monkey patched a lot of stuff and it kind of solved some problems but not others. On the other side there was Ember query params and Ember query params solved a slightly overlapping but different set of problems and it also solved them quite well but it had some bugs as well and lots of custom hacks which people have done and if you've done this either you have loads of subtle or not so subtle bugs and it's broken in subtle ways or I hate you for making me actually have to write this myself. Is this the handling of query params? Or is it the integration of the query parameters to query something, some sort of data set? No, it's not to do with query data sets. It's purely to handle parameters? Yeah, so it's to handle parameters in your application URLs, it's not to do with querying data stores, Ember data is always supported to query parameters for querying stuff on the back end or you can use jQuery or however you want to load data. So query params in Ember and not Ember data is ambivalent to what data store you're using, you could be using Ember data, you could be using jQuery or you could be using nothing, you could have no back end data store at all and it could be everything on the client side. So there are query params in master, there's this horrible URL which I'm going to leave up for a while because although it's merged into master unfortunately the docs aren't merged into the website branch and there has been some back and forth on that about whether or not they should be merged because it's only available behind a feature flag. So this is actually a URL to the pull request which will be merged eventually, hopefully soon. But the docs, there is full documentation to this and they will eventually be on the website as a guide. I'm going to go through basic examples of how to use them, it's a relatively simple API. So the main thing is that query params are a routing concern so you have to define the query parameters that your routes are going to respond to and you do that in your router.map statement. You can define different query params for different nested routes and this kind of looks simple, it's quite easy to understand, you give a list to each resource or route of query params that are being responded to. However, it does get slightly complex and there are some slightly unexpected things because query params are global and if you're not careful this can kind of go really wrong for you. So I'm going to kind of go through some of the examples of how this can go wrong and how it can go right. Here's an example of the URLs that show up in the browser URL bar. By the way, I'm just using paths here but this does work perfectly with push date or hash URLs. So it doesn't mean that you have to use push date, it's supported by older IE versions if you're lumbered with those. The interesting thing here is that the first two are probably what you'd expect. You can respond to the post URL response to sort and direction parameters as defined and the post resource which is the nested resource responds to show details because that's what's expected. But you'll notice here that actually you can have all of the query params that are registered for both the child and the parent and that happens when you're accessing the child route. So this is because in Ember I'm like server-side frameworks that I mean I certainly come from the server side and more than the client side background. You may be used, you're probably used to one route being active at once, I mean that's kind of the thing in Rails, you've got one route even though the URLs are nested you probably won't have nested resources where multiple things are nested. Where multiple things are active at the same time but in Ember it's very common to have multiple routes active at the same time and that means that query params are kind of additive among parent and child routes. How do you actually access these? You get new arguments in all of the hooks so before model, after model, model obviously, set up controller and render template anywhere that this stuff is usually passed in. One gotcha if you're adding this is that the transition object used to be the last argument in the functions in the hooks but now there's additional query params. And this argument this actually varies depending on if you have query params defined for the route or not. It was kind of a compromise to have a nice API which was worked out with the hula cats. I don't think this actually will really matter because I don't think it's very common to be actually using the transition object that's passed into the model hooks. It's quite a recent addition anyway and it's very rarely used but it is something to watch out for that if you define query params on a route it will pass in query params transition but if on your index route you didn't have any query params to find it would just pass in transitions you won't get an empty query params object. You can transition query params so you just pass in a hash with the key query params as the last argument in transition too. You pass in the value for what you want them to be and it sets them in the URL it's updated you can also use replace with the alternative transition to if you don't want to add a state to your browser history. Which obviously doesn't work in all cases but it works where that's supported by the browser and if it's not supported by the browser it will just be the same as if you used it without query params. I.e. it will add a state to the history and there's just not much you can do about it. And it works in the link to helper so this syntax is probably going to change unfortunately it looks like there's been slightly too many issues with query params clobbering link view properties. So if you were to have a query param called active for example that will break everything because link view hasn't active property which it uses to set the CSS class. I think another one was state so if you have a query param called state and pass it into a link to helper there's an infinite loop because state is actually relied on as a property for link view. So that will probably be changed to something like query direction equals asking and there will probably be some kind of convention as to the naming what you pass it into the link to helper. And there's just a link to it. I will be kind of tweeting my slides and maybe passing them on to someone to post on the meetup group or something so that if anyone wants to get to these links without copying them down now you'll be able to. But this is the issue where this problem is discussed and the result the resolution will come into eventually. So another slightly unexpected thing maybe if you're not used to it is query parameters are sticky. So let's say you're currently on a URL and you've got sort param set and then you transition the direction params. The sort param will stay the same as what it was and this lets you this lets you kind of build up stuff additively. So obviously if you change the sort direction from a link you probably don't want to then clear the actual value that's sorted by so it lets you kind of have lots of links to build up a state from stuff rather than having to have every link have every query param explicitly listed. And so that's the same with the link to helper obviously. When you do want to clear query params you just pass in false and they're cleared. That's quite simple and expected. Same with the link to helper passing in false clears them. Boolean query params don't actually have a value. So if you pass in true as a value to a query param it doesn't get set as you know param equals true. It's just present without an equals in it. And this allows you to do much simpler logic in your root hooks because obviously if it was true or false and that or zero one or whatever convention you might choose. They both evaluate truthy in JavaScript. So let's you just do if params dot is showing details and it will just work okay because it will be either null or true. So and it will actually be Boolean true. It won't just be a string true. It will be actual Boolean true. This is kind of a gotcha and this isn't a query params gotcha. This is an ember gotcha, but it's actually relatively not well known and the observers guide has only recently been improved. So if you haven't read the guide to observers in the last like two or three weeks, go back and read it because there's almost everyone misunderstands observers. It took me like a year of using ember until I actually realised some really big gotchas about observers and I was like, oh, I've got loads of bugs in my application. I wonder that's happening. So that's buggy. This is the solution to it. You in observers you should generally wrap your actual logic in an ember dot run dot once function. So this will this will do pretty much the same thing except it won't break horribly when you try and transition to this route. This I mean query params happens to expose this really badly and that is because this observer will fire as the root is set up and at that point you're in the middle of a transition and it will try and cancel the current transition and retransition into what you've just transitioned to. So it's kind of horrible. I'll just try and kind of explain why that is very briefly observers are synchronous and whereas computer properties properties generally aren't. So as soon as this value changes, your observer will be called. So as soon as checked value changes at all, your observer will be called straight away and that means that bindings might not have synced. If you're in a transition, the transition won't have completed. If you're observing multiple properties, then your observer will be called multiple times. So if you're observing three properties and they all change in the same run loop, your observer will get called three times and the properties will different each of those three times until the final time. It's finally updated and the properties of the values that you would expect them to be. So this is in the observer guide and there's some other stuff in there as well that's new about them. Observers are kind of one of the things in Enver that are much more complex than it looks at first glance. So go and check that out. Another thing is that query parameters are global and there was quite a lot of discussion about this on discuss during the implementation phase and there were some proposed solutions where there were some kind of weird syntax that didn't look like query parameters. So Tim Berners-Lied proposed matrix parameters, which is kind of like query parameters in path segments separated by semicolons. But it was decided that it just kind of looked too weird and people think it will think it's weird. It also breaks some URL parsing stuff like you end up with loads of broken links on the web because they don't expect semicolons to be in them. So it was decided to just deal with this fact that they're global and not have some weird syntax. And that means that if you have two paginated resources, this is one that was actually an issue recently on GitHub. If you have two paginated resources and you call both of the params page, even though they're not nested, if you go to kind of like page four of the posts and then click a link to comments, you'll end up on page four of the comments. So essentially because they're global, each query param represents a part of application state. And if you want it to represent two different application states, then you have to use different names for them, which is, it's not that bad, it's not that bad, but it's something that might trip you up. And if you really, really want both of the params to be called page just because you want URLs to look like that, then you may kind of be able to hack around it with like ReaderX, but it's going to be really ugly. I don't know why that's happened. So what's to do? Model query params versus control query params. So this is something I've been meaning to work on, haven't got around to yet, but currently all query params are expected to be model query params. And what I mean by that is that query params are treated very much the same as dynamic segments in your routes. So they're treated as if they represent the model and state of the model. And if you transition query params, it's going to hit your model hook again, you know, if appropriate. So if the query param affects the right route and it's the top of the tree of routes that change, so basically if a change to that dynamic segment would have hit the model hook, the query params will hit the model hook. And this is generally fine, but slightly inefficient. And what I mean by that is that if you could have sorted on the client side or if you can sort on the client side, that's kind of a common use case. You've got a list and it's already loaded. It will still hit your model hook and it will load the list again from the server unless you manually cache it. There's going to be some work done to flag that a query param affects only client state. And what that means is the model hook will only be hit the first time and then you can change the state on the client side without hitting the server again. You can cache this relatively easily just using some kind of hash dictionary object in your route. But it will be built in in the future and it will be slightly nicer in API terms. A nicer way to bind query params to controller state. So a declarative way of doing the observer thing I was showing you earlier. I think that's probably the most common use case to be honest is binding to controller state. So you will want your query params to directly map to stuff on the controller. And at the moment you have to assign it in, you have to set it in one of your root hooks and then you have to bind and have an observer on the controller to set it back to the query params. So it will be nice to have a one word API for that to do it simply. At the moment you can't specify query params for application route. It's just because application route isn't defined in your app.rooster.map state. So there's no real big reason that this is not possible. It's actually quite an easy implementation but the API is just not there. You can mitigate this either by wrapping, basically by wrapping all of your routes inside a parent resource. But that's kind of not great if you don't want to do that. It doesn't have to affect your URLs because your parent resource that you wrap everything in can have a path of slash. But it does mean that the names of all your chart route will have to change appropriately. And really, who knows? So one of the great things that I love about EMBA is the fact that it's really aggressive about seeing real world usage and kind of evolving best practices and wrapping those into the framework. So once this is out for a while and people start using it, hopefully common patterns are going to be seen and adopted as best practices in the framework. So I guess that's really it. Kind of my takeaways from doing this. So this is kind of the first time I've really dived into contributing to EMBA. I've done kind of a few very small pull requests before and this kind of touched everything. So there's kind of a few microlibs in EMBA. There's the router.js slib, which is usable without EMBA for handling all the routing stuff. And there's root recognizer, which is a dependency of router.js. And that actually handles kind of like the parsing stuff for parsing URLs and stuff. Routing is hard in general. Nested routing is particularly hard. Synchronous nested routing is even harder. But EMBA's router handles this in a really, really good way. I certainly haven't seen any other frameworks really tackling this in such depth. The problem is that it's really hard to actually understand it. I feel like it took like a month of hacking on the router for me to actually get it. So it's really, really worth digging into the code. It's readable and it's not actually that big. If you go and read the main file in router.js, you will instantly level up your EMBA programming because the router is really the centre of everything. And that's it. So go and use query prams and enjoy. Any questions? Is this a small application that uses query prams? So there is, what is that? I actually did a JS fiddle, which was posted on the original pull request, but that's not going to be that easy to find. It's PR3182. I know this because I've been to it a million times. I do actually have one and I kind of have it on my laptop, but I put it up somewhere and tweet it or put it somewhere else. So wherever I put it, I will make sure I send it to the organisers and they can post it somewhere everyone can see it. But I do have something. It's the EMBA, the Thompson mail thing that's on the EMBA JS homepage but with sorting basically. So I'll post that if you're interested. I had one about the sticky prams. If the root changes, is that sticky or is that not sticky at that point? So if you go and post to a comment, that's for example, is it still sticky prams? Yes, it would. So once you start using it, it kind of makes sense. So if posts and comments both have a pram named page, they both have the same pram, then it will stick between the two. So if they have differently named prams, they will stick to the individual roots. So you'll go back to posts and it will store that page in the root state. You go back to comments and it will go back to the page you were on previously unless you explicitly link to or transition to with the crew parameter equal to full switch then clear it. So if you're using it for pagination, like a lot of your links, like maybe the link to posts would probably have page equals false in it so that it always links to the first page or page equals one, whatever. Does that mean every time you navigate away from your chunk of your site, you need to clear down all the comments you've been using in that chunk? If appropriate. So I mean with pagination, yes, you would want to do it every time but often you would want to store that. If you have a specific view or tab open, maybe that would be stored in the state and you'd have to clear that if you wanted to not link to, not go back to that state. Could you use the Will Transition event? You could use Well Transition. You can do it in Setup Controller. So if you wanted to clear them down in Setup Controller you could then re-transition out of that. I think actually maybe that would be hard. Probably Will Transition is the best way to do it. Or linking to the query parameter equal to false. It usually makes sense but obviously for some stuff it can get annoying if you really want to clear everything. But you can just link to query parameters equals false and that clears all of them so that's probably the easiest way if you want to reset your state when you re-enter a route. Is there a reason that query parameters are separated just from general grounds? You can do quite a lot of this with normal prams, with dynamic segments. It's really much more useful for controller state than the model state. So it's really, although it's slightly inefficient right at the moment if you have some part that's controller state and some part that's model state it almost always makes sense to use the controller state as query prams. And this is for the same route. So sometimes you might use a nested route where the parent has the model state as a dynamic segment and the child has the controller state in it. But essentially there are just some cases where that's really difficult to do. Roots without dynamic segments for example make that really difficult to do. Where you have the option. So if you want a list of posts where you can just hit slash posts or you can hit slash posts slash page one for example that means you're going to have to have like two routes and that's going to get really annoying. So that's going to be painful. It doesn't actually allow you to do anything that's completely impossible to do right now with dynamic segments but it allows you to do a load of stuff a lot nicer. That's essentially it. And eventually it will allow you to do some stuff that's impossible but to do it at the moment. I think the use case I've hit already is like Google Analytics wants to know about your search URL and it expects a parameter. Right, yeah. You can't do it. Yeah, that's definitely one use case. It's just going to be a lot nicer than serialising stuff. It's a mapping is one where it's incredibly useful if you've got that long zoom level. You can do that at the moment and you can serialise that but it's just going to be a lot nicer to do that in a way like... So it's really useful in link tools. So let's say you've got a map and you want to have a link that zoom in. If you do that with a dynamic segment you're going to have to build a controller computed property that has the current object but then altered with a higher zoom level and then use that in the link to helper. This kind of lets you transition and link to smaller units of application state rather than the current link to helpers which require either the new model or the entire dynamic segment to be passed in all in one go. So I guess that's probably the best way to describe it is it kind of lets you break up your application state into smaller controller state into smaller little parts that you can link to automatically rather than having to link to the whole shebang in one go. I have three questions. First is about security. You said that it's pretty global what you're doing in the parameters so has Ember do with Alpes do you need to be concerned about people perhaps knowing the fact that you're using Ember and oh by the way you can just set global? Essentially no because basically anything that you can do on the client side you can do So you have to have some sort of defensive coding in there somewhere? No I mean so it's essentially if you're building a client side application you can't do any auth in it you have to assume that you can't obfuscate anything or code defensively against anything like anything that's in your source code you send to the browser then they can see and they can change and they can do whatever they want with you have to do all of your auth on the server and that's just how client side apps work so it doesn't have any impact on that that client side applications in general are any different to basically I can't remember my second question but the third question is was your talk for using the technique you suggested today or against it? I got an impression that it was against it No it's for it so I developed this and filed the pull request for this so I mean yeah query parameters are great for certain use cases You remembered the second one? No Well I'll be around so ask me a few It might be that fair but you mentioned tapping to the control of state and do you have any sort of timeframe in mind? Last time I was asked this I had a matter of month and that was about a month ago Yes I could say the same thing but the problem is that I actually don't really work on Ember much anymore I changed projects last month at work and I'm back on a much more standard server side application so I have less time at work but I do really want to get this finished anyway so it's definitely something that I will look at eventually and hopefully we'll get time to look at it soon Sorry I can't be more specific Any other questions? Okay well thanks everyone for listening