Saturday, May 24, 2014

Knockout Trees and Fancy CSS buttons.

For the past couple of weeks I have been working on some pages using knockout.js that have a fairly complicated UI.  A few of the elements in the pages don't look or function like standard HTML elements and there are a lot of lists that could contain lists (essentially a tree).  While I would have loved to use angular for this, I ended up going with Knockout mainly due to there being a lot more familiarity with that framework throughout Sonoma (myself included) and there was a short turnaround time.

I put together a quick demo of some things that I thought were interesting on this JS Fiddle.

To create a tree like structure, I defined a JS constructor function Node that will act as typical tree node containing a Label and a list of children nodes.  I created a function on the Node to add a child to make view cleaner and I had my objects defined.  I applied bindings to the "root" node and I had a pretty standard data tree.

In my HTML view I created a "template" for each node so whenever a new node was created I automatically use that template.  In each template I needed to expose 2 actions.  The first one is a button that would add a child Node to the current Node.  That button just calls the prototype function that was defined previously.  The second button is to remove the current Node from the ObservableArray that it is currently in.  To do that I knew that the parent scope would be the parent node (a new scope is created for each template), and that I could remove it from the collection using the Remove method on the array.  Finally I put a check on there to make sure that the $parent isn't equal to the $root so the root node never gets removed.

For the buttons I ended up changing their styles to look dramatically different.  For the delete buttons I just wanted them to display as a "X" icon so I changed the background of the button to the image, removed the border and changed the cursor to a pointer to make it more obvious.  The other thing I had to do was to remove the focus outline of the button.  To do that I added an :active pseudo selector to remove the outline that is added.

For the Add buttons I wanted to display text as well as an image so I needed to do a little more work.  First, I added an underline to the text and changed the color to make it more apparent that this was clickable.  I then applied the same styles ass the delete button except for the background image.  For the image I added a a ::before selector to put an image before the button.  Now those images will be displayed with the button and are clickable just as if they were part of the button itself.  I also don't have to remember to add that image if I need to add a similar looking button elsewhere in my application, which would be pretty likely.


Thursday, April 3, 2014

Application-Wide JavaScript Autocomplete for Rails

For my skills application site I wanted to add some more front-end JS code, but wanted to start with something simple.  So the first thing I could think of that was pretty easy to do was adding an autocomplete to a couple of the search boxes.  The search boxes allowed  you to search based on the skill name.  Unfortunately there are over 1500 skills.  So making sure that you query the right skill is hard to do.

To create the autocomplete I decided just utilize jQuery UI's autocomplete control.  For my initial pass I decided to not use the service based approach and go with a static source of values.  To access these values I decided I would put the list of values in a data attribute on the actual autocomplete control itself.  The JavaScript would just then pull those values from that attribute.

Here is what I came up with:

  <%= text_field_tag :skills, params[:skills], :id=> 'skills_autocomplete',
        :data => {:skills =>  SkillTotal.retrieve_skills() } %> 
<% content_for :javascript do %>
  <script type='text/javascript'>
    $(document).ready(function(){
      $("#skills_autocomplete").autocomplete({
        source: $("#skills_autocomplete").data("skills")
      });
    });
  </script>
<% end %>

It ended up working out pretty well, however in my form JS I was querying the control by its ID.  Every time I needed an autocomplete I would essentially have this code on each one of my views.  I decided that this was good, but I could do better.  I wanted to make it more DRY.

I created a global.js file where I would put an on load function and set up the autocomplete so I didn't have to put it on each form.  Instead of going by the ID, I went by a class as well.  In the end it looked like this:

<%= text_field_tag :skills, params[:skills], :class=> 'autocomplete',
        :data => {:autocomplete_data =>  SkillTotal.retrieve_skills() } %>
(function(global){
    global.App = global.App || {};
    global.App.autocomplete = function(){
        $(".autocomplete").each(function(){
            var field = $(this);
            field.autocomplete({
                source: field.data("autocomplete-data")
            });
        });
    };
}(this));

$(document).ready(App.autocomplete);
I soon found out that my code wasn't working.  A little bit of digging and this has to do with the turbolinks gem which is included by default with Rails.  A little more digging and I now my JS looks like this and is running on multiple pages.

(function(global){
    global.App = global.App || {};
    global.App.autocomplete = function(){
        $(".autocomplete").each(function(){
            var field = $(this);
            field.autocomplete({
                source: field.data("autocomplete-data")
            });
        });
    };
}(this));

$(document).ready(App.autocomplete);
$(document).on('page:load', App.autocomplete);



Wednesday, March 26, 2014

Setting up a daily task on Heroku

When I set out to create the Skills App site, one of the main things I wanted to figure out was how to scrape the data on a daily basis and automatically insert into the database, preferably at the same time each day. I started out with some quick googling while I was developing the app, but nothing obvious stood out. There were a couple of ways that seemed to be repeated on how to get data into a rails app. One was having a rake task, and the other one was via a seed file. I wasn't sure what to do so I tabled it, and decided that it would be one of the first things that I figure out after the initial deploy.

After the deploy, my good friend Scott Parker, who makes awesome dragon games, gave me some feedback on the site after reading my initial post.  He suggested that I take a look into using rake and the scheduler add-on for Heroku. I took a look at rake and played around with it a bit. I also found a useful railcast about it which helped me figure out what I needed to do.


So I took the majority of my scraper code and put it into the rake task and tested it locally to make sure it was working, then I set up the scheduler to run around midday, uploaded all of the data I have been collecting every day and anxiously waited to see if it would automatically add today's data.



Success!  Data from today!

Enjoy the site and please feel free to reach out to me with feedback, feature requests, or anything else.  For those that have given me feedback, I really appreciate it and hopefully I will implement your features soon!


Monday, March 24, 2014

Deploying to Heroku

When I deployed my Skills Compiler rails app the other day, I ran into a few issues deploying to Heroku that were worth mentioning.  
  1. Deploying from a folder that is not the root.

    As stated on the Heroku website:
          Heroku apps expect the app directory structure at the root of the repository. If your app is inside a subdirectory in your repository, it won’t run when pushed to Heroku.
    I knew there had to be a way around this. As someone that has created lots of project structures in their career, I typically don’t put the main app in the top folder. I have found that you can paint yourself in a corner by doing that. When I create a project, I want to include everything that is necessary for it, which could mean other apps, documents, or whatever.

    I ended up finding this site:
    https://coderwall.com/p/ssxp5q that had the same issue and solved it by pushing a subtree. It is as simple as this command:

    git subtree push --prefix subfolder heroku master

  2. Make sure your git ignores are correct.

    When I pushed to Heroku using the command above, nothing ended up working.  The console logs weren't much help (just kept giving me generic errors), and when I used the console to list the files, everything appeared to be copied over correctly.  After some digging I realized that none of the rails commands were working on Heroku.  I eventually found an error that pointed me to an issue with something missing from the bin folder.  I found that because I was using the default .gitignore file from GitHub with a few altercations, that the /bin folder was globally ignored due to .Net & (I believe) Java.  After a few modifications to the .gitignore file I finally got my site up and running on Heroku.




Sunday, March 16, 2014

Skills Application

I have been working on this application for a few weeks now, and I am finally ready to release version 1.0 of it.  The site, Skills Compiler , (I suck at naming) was inspired by a few things, but these in particular. I wanted to teach myself a new language, I wanted to do some more general web development, and finally I was inspired a bit by the Passionate Programmer: Creating a Remarkable Career.  If you haven't read the book, I definitely recommend it.  In the book, one of the points it makes is keeping up with latest trends making sure your skills are up to date, and it kind of inspired me to think about ways of finding the trends in the development community, which is something I personally wanted to improve on.  

All of this combined with my curiosity started me down the path of creating this app.  The app displays data that I have scraped from the Careers 2.0  in a few different ways.  The app displays the totals per day, as well as the overall totals for a given tag.  A tag is counted when it is listed for a given position.  For example, this position by Sonoma Partners for a Salesforce Developer would add 1 to the daily count for Java, visualforce, apex-code, soql, and JavaScript for each day the job is listed.  

Obviously this is just a small snapshot of the jobs that are out there because it currently only looks at one site, however there are still some interesting things that you can gather from a month and a half worth of data.

Wednesday, February 19, 2014

CSS Solar System

In my quest to expand my HTML/CSS I stumbled across this exercise at Codeacademy that showed you how to create a simple animated solar system using only CSS.  I completed the exercise and added a bit more to it as well.  I took his example and expanded upon it to include all of the planets, a few moons, and some rings around some planets.  After I added a couple planets I knew that there was a pattern emerging and decided to use SASS to make my CSS cleaner, as well as it gave me an excuse to use it.

Wednesday, December 18, 2013

Writing Elegant HTML

The other day I was thinking to myself, "Self, I wonder if there are any books on writing elegant HTML and CSS."  I'm sure there are I thought, and spent some time looking on Amazon for a book.  I was hoping for something that would essentially teach me the correct way to do things since I am pretty much self taught in the area of web development and would like to know what I am doing right and what I am doing wrong.  Unfortunately I didn't find a book that was suitable for what I was looking for.  However I did find a site that I found just as good, if not better. The website, Webplatform.org, has a lot of nice tutorials on it, with explanations why to do it that way.

So far I have only gone through the HTML and part of the CSS tutorials, but I have already found plenty of flaws in the HTML I used to write and definitely plan on changing the way I write it to become more semantic of the page I am writing.  By writing html that is more semantic it makes everything clearer to other developers what the element does, and it also helps out those with disabilities that need to use things like screen readers.