How do I ensure my JS ERB is Turbolinks 5 friendly? - javascript

I have some simple JS ERB files that work perfectly the first time around. However, the issue is that when the trigger for the JS is pressed multiple times, it doesn't work client-side (even though it works server-side) - which I suspect is related to Turbolinks 5.
One such example of my JS.erb is this:
$("#a-<%= #answer.id %>-accept-answer i.accepted-answer-checkbox.fa.fa-check-square-o").addClass('fa-check-square voted');
$("#a-<%= #answer.id %>-accept-answer i.accepted-answer-checkbox.fa.fa-check-square-o").removeClass('fa-check-square-o');
That's in my Questions controller & /questions/accept_answer.js.erb.
But, right now, my questions.coffee file is blank.
What's the best way to tackle this?

Honestly, CoffeeScript has Ruby-style interpolation, so the easiest way to convert those would be to just go and do something like
$("#a-#{#answer.id}-accept-answer i.accepted-answer-checkbox.fa.fa-check-square-o").addClass 'fa-check-square voted'
$("#a-#{#answer.id}-accept-answer i.accepted-answer-checkbox.fa.fa-check-square-o").removeClass 'fa-check-square-o'
But what you're trying to do, would probably be better served by toggling those three classes, having them in an initial state that opposes each other, so something like:
$("#a-#{#answer.id}-accept-answer i.accepted-answer-checkbox.fa").click (el) ->
$.each ['fa-check-square', 'voted', 'fa-check-square-o'], (_, val) ->
$(el).find('i.accepted-answer-checkbox.fa').toggleClass val
Of course, I could be making it too complex, but this seems to solve the problem of toggling the classes that are desired.

Related

How to move .js from View to Separate asset - Ruby On Rails

This is a seemingly easy problem but it might not be. I am new to rails. As such I am still learning the in's and out's of the asset pipeline. I have an understanding of the assets/stylesheets and can get those to edit my view. However, I cannot get my assets/javascripts to work. The js does work if it is embedded in the view however.
I was hoping someone could take a peek at the source: https://github.com/Brownkyle219/clemson-sustainability
and you can see it functionally here:
http://clemson-sustainability.herokuapp.com
(I am aware that there is a routing issue when you click on the other tabs). Ignore the google charts stuff. My main focus is at the bottom of index.html.erb about the slider. All I want to do is move that script to a separate file in assets/javascripts. Any advice would be great! Thanks
You need to wrap your JS in $(document).ready(function({ yourCodeHere })
Otherwise, the JS gets executed before the elements they target are actually loaded and will not work.

Inline Javascript: Is it a good practice?

I have many view templates where i have inline javascript specific to that view.
for eg:
app/views/something/index.html.haml
.some-id
%h4 Something
#this javascript is not reused anywhere. Used only in this view
:javascript
$(document).ready(function() {
$('.some-id').addClass('something')
})
Is it a good practice to have the views like above?
It is definitely a pain to maintain inline javascript across multiple views. So i started moving them slowly into one single javascript file. But i am not sure if that's a good thing because, all the javascript will now get executed for all the pages.
So which is the best place to put view specific javascript?
If you are worried about page load time, you should use something like loadjs. It is just not maintainable to be place JS in your views like that. For super simple projects then maybe, but in general you should stay away from it.
Another thing to note is that browsers will cache your javascript when it is loaded from a file. They cannot do this when it is inline because the HTML is rendered every page load. So you probably are looking at an overall performance loss when doing it inline, even without loadjs.

What is the syntax for calling functions defined using WinJS.UI.Pages.define from the associated html?

Since there is a distinct possibility that I'm doing something wrong, I'd like to describe what I'm attempting to accomplish, in case there is a better way of doing it.
Platform: Windows 8 app using Navigation Template for HTML5/WinJS.
I have a few PageControls that query for data and use d3.js to visualize the resultsets.
I have another PageControl(dashboard) that uses a WinJS.UI.ListView to provide links to those pages/graphs. Currently, I'm using some static images in the ListView. What I'm trying to do is access the graph pages and present a "smaller" version of the graph on the selection screen.
Some of the things I've tried:
- iFrames do not appear to scroll (and the results look pretty ugly).
- I haven't been able to figure out how to do a screen shot programatically (this would be the best option, because I could then use the same technique when sharing the graph using the sharing contract).
- I've tried doing a Page.render, but it only seems to work if I have the call to my draw() function somewhere within the html page. In other words, it doesn't appear the the ready() function is being called as part of render. So, I've moved the drawing code into the html (which I really do not like), and that seems to work OK.
What I'd like to do is to move the draw function back to the Page.define and call it from a one line script in the html (unless there is a better way), but I haven't been able to get the correct syntax figured out.
I'd appreciate any pointers on the syntax or advice on better ways to accomplish the task in general.
I would suggest just putting the drawing code in a separate .js file that you can reference from anywhere in your app. Set it up like the following:
WinJS.Namespace.define('My.App.Namespace', {
drawingFunction: function () {
//code goes here
}
});
Save that to a file called drawing.js and include it in your default.html. Then you can call My.App.Namespace.drawingFunction() from either html or javascript.

Custom View Engine to solve the Javascript/PartialView Issue?

I have seen many questions raised around PartialViews and Javascript: the problem is a PartialView that requires Javascript, e.g. a view that renders a jqGrid:
The partial View needs a <div id="myGrid"></div>
and then some script:
<script>
$(document).ready(function(){
$('#myGrid').jqGrid( { // config params go here
});
}
</script>
The issue is how to include the PartialView without littering the page with inline tags and multiple $(document).ready tags.
We would also like to club the results from multiple RenderPartial calls into a single document.Ready() call.
And lastly we have the issue of the Javascript library files such as JQuery and JQGrid.js which should ideally be included at the bottom of the page (right before the $.ready block) and ideally only included when the appropriate PartialViews are used on the page.
In scouring the WWW it does not appear that anyone has solved this issue. A potential way might be to implement a custom View Engine. I was wondering if anyone had any alternative suggestions I may have missed?
This is a good question and it is something my team struggled with when JQuery was first released. One colleague wrote a page base class that combined all of the document ready calls into one, but it was a complete waste of time and our client's money.
There is no need to combine the $(document).ready() calls into one as they will all be called, one after the other in the order that they appear on the page. this is due to the multi-cast delegate nature of the method and it won't have a significant affect on performance. You might find your page slightly more maintainable, but maintainability is seldom an issue with jQuery as it has such concise syntax.
Could you expand on the reasons for wanting to combine them? I find a lot of developers are perfectionists and want their markup to be absolutely perfect. Rather, I find that when it is good enough for the client, when it performs adequately and displays properly, then my time is better spent delivering the next requirement. I have wasted a lot of time in the past formatting HTML that no-one will ever look at.
Any script that you want to appear at the bottom of the page should go inside the ClientScriptManager.RegisterStartupScript Method as it renders at the bottom of the page.
http://msdn.microsoft.com/en-us/library/z9h4dk8y.aspx
Edit Just noticed that your question was specific to ASP.NET MVC. My answer is more of an ASP.NET answer but in terms of the rendered html, most of my comments are still relevant. Multiple document.ready functions are not a problem.
The standard jQuery approach is to write a single script that will add behaviour to multiple elements. So, add a class to the divs that you want to contain a grid and call a function on each one:
<script language="text/javascript">
$(document).ready(function(){
$('.myGridClass').each(function(){
$(this).jqGrid( {
// config params can be determined from
//attributes added to the div element
var url = $(this).attr("data-url");
});
});
}
</script>
You only need to add this script once on your page and in your partial views you just have:
<div class="myGridClass" data-url="http://whatever-url-to-be-used"></div>
Notice the data-url attribute. This is HTML5 syntax, which will fail HTML 4 validation. It will still work in HTML 4 browsers. It only matters if you have to run your pages through html validators. And I can see you already know about HTML5
Not pretty but as regards your last point can you not send the appropriate tags as a ViewData dictionary in the action that returns the partial?

RJS/Javascript conventions in Rails

I'm starting to look into the whole world of RJS and Prototype/jQuery in Rails and am a little bit confused. There seems to be no clear line of where to use one or the other.
Say I wanted one of the "Active, Hot, Week" tabs like the ones here on SO. When pressing one of them, I want to remove a CSS class (like "active-tab") from the one I was on and add it to the one I clicked on. Then I also want to reload the div containing the items and put in the new items into it.
Seems the class-changing thing would be easiest to do in pure javascript, say put the code in application.js and then updating the div with the content would obviously be easiest in RJS. But what should one do?
If you're comfortable with writing JavaScript then by all means use JavaScript. There's nothing wrong with that; you don't have to use RJS just because it exists. In fact you'll probably find that its abstractions get in the way.
However, if you'd rather write Ruby code that generates JavaScript, just as you write Ruby code that generates SQL in ActiveRecord Migrations, then RJS is the right tool for the job. Or you can use both: RJS for fairly simple things and then drop down to JavaScript for more complex behaviour. Use what feels right to you.
If you want to give users that ability to link to the generated page directly, then definitly go for a static page. Using AJAX breaks the back button unless you use something like Really Simple History (which is not 100% cross browser), so going the JS route with your page navigation will almost certainly cause some of your users problems.
That said, what you have discussed already would be fine, I think - just have a class change in your RJS file, then you might even find it useful to update the div contents using page.replace and a partial:
page.replace(dom_id, :partial => #page_content);

Categories

Resources