Rails is always suggesting us to use DRY concept in our codes, and there are plenty of ways to achieve that.
Here I am gonna explain how we can achieve the DRY concept in adding JavaScript functionality to our Rails applications.
For explanation I have taken jQuery Tokeninput as an example.
Usually we add a plugin to our app in the following way.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(document).ready(function() { | |
$("#token-input").tokenInput("http://my-own-app.com/tokeninput/json", { | |
preventDuplicates: false, | |
tokenLimit: 10, | |
hintText: 'Type to Fetch Data', | |
noResultsText: 'No Data Found', | |
searchingText: 'Fetching Data', | |
onAdd: function(item) { alert('added successfully') }, | |
onDelete: function(item) { alert('deleted successfully') }, | |
prePopulate: [{id: 7, name: "Ruby"}, {id: 11, name: "Python"}], | |
theme: 'mac' | |
}); | |
}); |
Consider, the same html page is having auto complete for 3 elements. Then you have to repeat the same code 3 times. If the auto complete is added for many elements in the app, then you have to repeat the same code wherever it is necessary.
The same can be rewritten like below
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function call_auto_complete(call_class) { | |
$.each($("." + call_class), function(index, value) { | |
$("#" + $(this).attr("id")).tokenInput($(this).attr("data-url"), { | |
preventDuplicates: "false" === $(this).attr("data-duplicate") ? false : true, | |
tokenLimit: null == $(this).attr("data-selection-limit") ? null : $(this).attr("data-selection-limit"), | |
hintText: null == $(this).attr("data-hint-text") ? "Type to Fetch Data" : $(this).attr("data-hint-text"), | |
noResultsText: null == $(this).attr("data-no-result") ? "No Data Found" : $(this).attr("data-no-result"), | |
searchingText: null == $(this).attr("data-searching-text") ? "Fetching Data" : $(this).attr("data-searching-text"), | |
onAdd: function(item) { | |
null == $(this).attr("data-on-add-call-function") ? {} : eval($(this).attr("data-on-add-call-function") + "(item.id, $(this).attr('data-success-update'))") }, | |
onDelete: function() { | |
null == $(this).attr("data-on-delete-call-function") ? [] : eval($(this).attr("data-on-delete-call-function") + "($(this).attr('data-success-update'))")}, | |
prePopulate: null == $(this).attr("data-selected") ? [] : eval($(this).attr("data-selected")), | |
theme: null == $(this).attr("data-theme") ? "mac" : $(this).attr("data-theme") | |
}) | |
}) | |
} | |
$(document).ready( | |
function() { | |
call_auto_complete("auto_complete"); | |
} | |
) |
In html.erb you can call the function like below
<% selected_countries = @user.countries.map { |c| { id: c.id, name: c.name } } %>
<%= text_field_tag("users[country_id]", {}, { :class => "auto_complete", "data-url" => "/users/get_countries", "data-duplicate" => "false", "data-selection-limit" => "10", "data-hint-text" => "Type to search Country", "data-no-result" => "No Country found", "data-searching-text" => "Fetching Countries", "data-selected" => (selected_countries).to_json }) %>
By this way, wherever you need the autocomplete, just add the class 'auto_complete', or the class whatever you want. Then that text field will be converted as auto complete dynamically based on the data attributes passed to the function. So this will drastically reduce your code repetition on JavaScript side.
And you can easily call this same function on ajax success also, no need to load the JavaScript file one more time.
Above mentioned code example is for jquery tokeninput plugin, but the same behavior can be used in other plugin implementation too.
No comments:
Post a Comment