Ruby on Rails - Railscasts PRO #136 jQuery & Ajax (revised)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I have received several requests to revisit the topic of jQuery and Ajax since the episodes I have dedicated to that are a little out of date so this episode will be a little more beginner focus but it's a fun topic so let's get started what I have here is a simple task list application where users can create a new task a sailor in karate and then they can create it and they can also check a task off or remove a task and that's it now each of these actions are requiring this page to fully reload in the browser but my goal here is to add Ajax so all this can be done without this page reloading now jQuery it makes accomplishing this much easier so it's nice that rails has jQuery included and ready to go out of the box it also includes this file called jQuery UJS which stands for unobtrusive javascript this adds some JavaScript behavior without you having to add any JavaScript code inline in the HTML you can see this in action if I try to remove a task I get this confirmation dialog which is handled using JavaScript but if I inspect this HTML element and take a look at the source for this remove link there is no JavaScript anywhere here but there is this attribute called data confirm and the jQuery UJS file is picking up on this attribute and adding the confirmation dialogue javascript behavior to this link there's also this attribute called a data method and this will trigger a delete request when this link is clicked instead of a normal get request done through the jQuery UJS file if you're curious about how this works you can find that jQuery UJS file within the jQuery rails project and if you check out the source code you can see that the data confirm attribute is mentioned right here on a link tag and so this is going to add special functionality to it now another handy attribute is data remote and this will help us allow and we're adding Ajax functionality to this application so the first thing I'm going to do is make it so when I click this new task link that it has the form inline instead of going to a separate page using Ajax so this is what that index template looks like where I have the new task link and to flip the Ajax switch I just have to pass in a remote option and set that to true now this new task link has this data remote attribute and when I tried clicking on it well it doesn't seem like anything happens so when you're trying to debug an Ajax issue it can be a little difficult at first but here are some steps to follow first check the JavaScript console and see if there are any errors in this case there weren't any next to check the network tab and see if their request was made and you can see the request for the tasks a new template is right here so we got a 200 okay s response back from the server so an error didn't happen on the rails end but if we check out the contents of this response this is actually HTML content which isn't really what to the JavaScript knows how to handle now there are many directions we can go from here we could try to slice out the form element from this response or we could have the server send a JSON data back and a parse that or we could have the server send a script actual JavaScript code back as a template and then it will automatically execute that which I find to be the most elegant and convenient option in most situations so here's the current new action in the controller and since we're not doing anything special here but rendering a template we can just make one specifically for JavaScript so I'm going to make a new file here let's call it new JSE RB and the first thing that should do is hide that new task link and if I check out the index template where I'm rendering that you can see I have this ID here called a new link so I can reference that within this script and I can do that by passing dollar sign parentheses and I can pass in a selector very similar to a css3 selectors so I can use a pound sign and say new link to reference it and then I can call the hide function on this now jQuery often maintains the current selection of elements so if you want to perform another function on this element is you can simply chain it so here I'm also going to insert the form code directly after this new link so I can just say after and then pass in a string of HTML which I'm going to render out through a partial so I'll insert some ARB content into here and render out the form partial right in line here but since I'm inserting ARB HTML directly into JavaScript I also need to escape it with the je method call and Ruby so there we go so this time when I click the link since it's coming through JavaScript is going to render out that Jas template which is going to have the content of that script we just wrote which inserts the form here now let me try creating a task and when I submit this is going to do a full page reload here because it's not set up to do Ajax requests for the form submission that's easy enough to fix if I go to the partial where I'm rendering out the form for the task I can just pass the remote as true option directly into here to add that data remote to attribute and then I just need the controller to respond to a JavaScript so I can to simply just add a template here because this has some special redirect behavior for the HTML version but I don't want the JavaScript version to do that so I can add a respond to block for a given format so I can change a behavior for HTML I want that to do the redirect behavior and for the jeaious version I'm going to leave a no block passed in here because I want to render out the template for this so this will be called created jst RB now there are several things I want to do here first of all I'm going to remove the form since the task was submitted and that's at the new task ID and I'll just call remove on this next I want to show the new link again so I just call show on that and then finally I need to insert the new task that was created into the index template and there's a div called incomplete tasks on there which is where I'll put it because every new task is incomplete and I can just append the task to it again here I'm going to render out the HTML using a partial so that's rendering out the task instance that we get from the controller and escaping it with JavaScript and let me close this off and it there we go so this time when I create a new task is going to do everything in an instant through Ajax without having to reload this page it hid the remove the form and showed the new task link and added the task here now I can easily repeat this process for the remove link because this currently reloads the page I'll do this quickly because it's basically the same thing inside the tasks partial is where I have this remove link and I'll just add the remote as true option and then in the controller destroy action I am doing a redirect here so I'll need and respond to block like I did in the create action for handling a j/s response and I'll make a new template here called a destroy dodge a STR B now inside of here I just need to remove the tasks so I need to reference it somehow but if I take a look back at the tasks partial you can see that this is inside of a form for editing the task record and so what I can do is use an ID that rails automatically assigns to it called edit task and then the actual ID of the task so I can just use a RB here to enter into the task ID from the task record I got from the controller and just remove this element and then clicking the remove link in confirming it and voila instantly disappears without a page reload next I want to tackle marking a task as complete which currently requires I hit this update button which is pretty clunky instead I would like it so that to this update button isn't there and just clicking the checkbox automatically submits the form and we can do that with some custom JavaScript I'm going to do this inside of this tasks J's coffee file which is a currently blank and this will use CoffeeScript but if you're not familiar with CoffeeScript and you prefer a Java Script with you're more comfortable with then you can easily go back to that by simply removing the coffee extension and that will just use a plain old JavaScript I'll just use this here and show you the CoffeeScript version at the end so what I need to do is listen to the click event on all the checkboxes so only to first select those I can do so by grabbing the Edit form element and then finding the input element inside of that where the type equals a checkbox and then for each of these I'll listen to the click event to pass in a function into here and so this will get triggered when the user clicks on it and for now I'll just display an alert dialog box saying that it was clicked now let's try this out reloading the page and now clicking the checkbox hmm doesn't seem to do anything we don't get our alert dialog and if I check out the JavaScript console there's a no mention of errors in there the issue is that this JavaScript has interpreted immediately when it's loaded in at the top of the HTML document but the rest of the document hasn't been loaded which means the checkboxes don't exist at this point so instead we have to delay this code until the Dom has fully loaded now jQuery provides a convenient way to do this by passing in a function into the dollar sign call and then so we can just move all this code directly into that function and that will be evaluated at once their full HTML document loads and you know what I just realized another issue with this and that is the class name is called edit task instead of edit form so always make sure that what you're selecting does exist on the page and now when I reload the page this time when I click on the check box it shows me the eclipse dialog so all we need to do now is have it submit the form to do this I'll grab the current element which is going to be the check box element and just grab the form of this so I can call parent and then fetch the form element of that and then I want to submit the form so I just pass in the submit function call and while I'm here I also want to remove the buttons of this form so I can do that quite easily by just grabbing the submit type and then just calling remove on this so that will grab it multiple elements and just remove all of them in one function call okay back to our app now when I reload the page the buttons will disappear and clicking on a checkbox submits the form it works and it goes the other way too if I click on a checkbox here it'll bring it back now I just need to make this form Ajax enabled like I did before so I'm going to do that really quickly here just passing remote to as true and then going into the tasks controller where I have this update action I need to respond to the JavaScript format and then I can make a new template here for a JC RB version now I'm just going to paste in the code for this template just to save us some time and my goal here is to move the tasks from one list to the other so first I'll see if the task is currently complete and if it is then I'll grab that task element and move it to the complete tasks and otherwise I'll move it to the incomplete tasks list by the way I've been using a lot of jQuery functions in this episode and you can find them all nicely documented on their site and they're split up into different categories here and the pin to function is inside the manipulation a section you can find it here and just see all the reference documentation for it to find out how it works with that done our application is pretty much complete we can uncheck this or check it to instantly move it from one list to the other or create new tasks instantly but there is a bug here if I create a new task and try to check it well there's two issues one is that the Update button is showing up and also that the check mark dozen to trigger the form submission now the problem is at this code right here is what will fix the issue but this only gets executed when the page initially loads and so won't apply to the new tasks to solve this one way is just to move this off into a function that way we can trigger it whenever we add a new task this is a good chance to demonstrate how jQuery plugins work basically is just a function that you can call on a selected element so what I'm going to do here is this is the way I want it to work so I select a form element such as the Edit task form and then I want to call a custom function on it and let's say submit on check and so this will add in that behavior now getting this to work is actually pretty easy you just call jquery dot f n and then pass in that name which is submit on check and set this to a function and then you just need to perform that same logic in here so I'll just paste this in however we'd want to reference the form element that we have selected so we can use this right here in this function to reference that selector we can use find on here to find the submit button and the check box which is inside of that form and that will allow me to find those elements and perform that same operation on any form I want and I also need to return this selector so that we can chain other calls on to it if we want to so with that done I can now change the create template which is where I'm rendering out the new task that was added which contains the form I want to apply that same function call to so it'll look something like this where I reference the form which is for that new task and just call submit on check on it let's give this a try now when I create a new task and it doesn't show me the button and also clicking on it will check it instantly so that works so our Ajax functionality is now complete and has promised let me paste in the CoffeeScript version of the JavaScript file here so you could use CoffeeScript if you want to I really like it I cover it more in episode 267 if you're interested now there's one more thing I want to point out before I go and that is in the index action or I'm listing out the tasks I am sleeping for one second and that's just more to exaggerate the fact that the page is reloading so that you can more clearly see the effects of Ajax and that's sort of just a quick technique to more simulate real-world activity where it actually takes a little while for the page to load because sometimes it's difficult to get that effect when it's just loading it on your local machine and that's all I have for this episode on jQuery and Ajax I hope you found it useful
Info
Channel: Railscasts Reloaded
Views: 42,349
Rating: undefined out of 5
Keywords: Ruby On Rails, Railscasts, Railscasts PRO, HTML, CSS, JavaScript, JQuery
Id: FBxVN7U1Qsk
Channel Id: undefined
Length: 14min 56sec (896 seconds)
Published: Thu Oct 23 2014
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.