Wednesday, March 26, 2014

Week 8 Day 3: Persistence is Key (or: Persistence in Object Keys... and Values!)

Major Activities of the Day: Today started with a couple of jQuery labs.  I ignored them, because I'm going crazy worrying about my project, and I feel like I'm learning more by doing an actual project than by doing predesigned labs that isolate me from many of the problems.  It's good to have that isolation and really focus on one problem initially, but once I'm more comfortable, it just feels like going backward.

We had lecture today about the power of remote: true in Rails.  It's basically a shortcut to setting up an Ajax form.  More info is available in the Rails guide about Ajax.  (Warning: the information there is written in CoffeeScript rather than plain JavaScript.)

We moved on to some more labs, which I continued to ignore for the above rationale.  Aaaaand there was homework.  Ignored.  Doing a project, is hard, ok, people?

Here's what's interesting, though: I had to figure out how to make the page persist data while the user was making selections, despite the fact that the page was displaying other things.  Here's what I mean: The page displays a bunch of links related to a particular issue, and the user can check off particular links.  The user might decide to check out a different topic, but then come back to this one.  I want the user to not need to re-check what was checked before.  So I used an array in the background that is updated when any checkbox is checked or unchecked, and when the user switches topics, it looks in the checked links array for which, if any, link have been checked before.

Here's a more complex example: I'm displaying recipes collected from Yummly's API based on a user's search.  These recipes are selectable via checkbox, and the selected recipes are displayed in a menu at the top of the page.  Here's where it gets challenging:

1) I want to let the user do multiple searches, and have the recipe data persist from search to search.
2) I want the user to be able to go back to a previous search, and have everything checked off as appropriate.
3) I want to store 2 pieces of information about each recipe: its name and its Yummly ID (which I can use to build a link in the form http://www.yummly.com/recipe/[recipeID]).
4) I want the user to be able to remove menu items by either clicking "remove" on the menu next to the item, or unchecking a box in the search.
5) When the form is submitted, exactly one copy of the selected recipes should be sent to the server.

Here's how I did it: There is a plain old JavaScript object in the background, which uses recipe IDs as keys and recipe names as values.  Every time there is a checkbox checked or unchecked, or the user clicks on "remove" next to an item on the menu, the object is updated.  Additionally, there is a hidden text area which is updated with the toString()ed contents of the object.  When the form is submitted, the contents of the text field are interpreted by the controller by converting the string to a hash using the ActiveSupport::JSON::decode method, and the hash can then be used to input information into the database.

I'm not sure this is the best pattern, but it works.

Then, to get the information back into the form if the user is editing again, I initialize the object with its contents (or an empty object if the recipes weren't filled in last time, or this is the user's first interaction with this form), and the text area is filled with the object's contents, right off the bat.  So the previous user data ends up in the form right away.  I used a similar method for the user-selected links.

Skills developed: More jQuery and Ajax, persisting data in two directions: form -> database, and database -> form

No comments:

Post a Comment