In a Rails 3.2 app I have a jquery function that renders a chart on a DOM element
#assets/scripts.coffee.erb
$(document).ready ->
$("#chart_container").do_some_stuff
#view
<div id="chart_container"></div>
I'm in the process of ajaxifying this view to enable the user to switch the data that is presented on the chart. The problem is that the coffeescript is not triggered via the ajax response.
If I put the function within some tags on the view, everything works fine, but this is not a very 'nice' solution.
Alternatively I know that it is possible to call functions from the view.js.erb rendered by the ajax response. Something like
#view.js.erb
$('#chart_container')['myFunction']();
But my javascript knowledge is limited, and I'm having trouble working out how to name coffeescript function correctly.
I need the function to be triggered when the document is ready. But I also need to be able to call the function manually via the ajax response. How should I set this up?
(I suspect this is a very basic javascript question, and not very well asked, but I appreciate any guidance).
You can wrap the code to a function at first
#assets/scripts.coffee.erb
$(document).ready ->
$(document).chart_action()
$.fn.chart_action = ->
$("#chart_container").do_some_stuff
Then call this function at your ajax response template
#view.js.erb
$(document).chart_action()
Upate Version
Thanks for #muistooshort's suggestion, it's better to use a custom namespace instead of polluting jQuery's, even in small usage.
So, refactor the above
# Custom functions for this app
class App
chart_action: ->
$("#chart_container").do_some_stuff
# Normal code for initializing page
app = new App
$(document).ready ->
app.char_action()
# view.js.erb
app.chart_action()
Related
I have a Rails application that uses backbone and coffeescript to make the interface nicer. However, I am running into some problems. I suspect the problem is a race condition. It is best to further clarify using a code snippet.
Here is a snippet of my coffeescript code:
class VGStream.Views.Scenarios.TypeWellScheduleForm extends VGStream.Views.Base.AjaxForm
className: 'schedule-form'
template: JST['backbone/templates/scenarios/type_well_schedule_form']
initialize: (options) ->
super
#typeWells = options.typeWells
render: ->
#$el.html #template #
#$('.well_type').val #model.get('scheduleable_type')
#setWellSelection()
#$('.well_id').val #model.get('scheduleable_id')
#$('.exclude').val if #model.get 'exclude' then 1 else 0
#calculateNetAcreage()
#
setWellSelection: ->
if #$('.well_type').val() == 'TypeWell'
wells = #typeWells.computed
else
wells = #typeWells.imported
wellSelect = #$('.well_id')
wellSelect.empty()
for well in wells.models
wellOption = $ '<option>',
value: well.get 'id'
text: well.get 'name'
wellSelect.append wellOption
The setWellSelection function populates a drop-down select box's options as you can see from the function definition. It has close to 1000 options. I agree that I should not allow as many options in a drop-down select, but that is a battle I want to fight later.
This code works perfectly on my local machine since there is no network delay on the localhost. The drop-down's options are displayed without any problems. However, on the network, with the application deployed on Heroku, the dropdowns do not display until I fiddle around with clicking on the dropdown list, and then it displays. Once loaded, then everything works correctly.
What I would like to do is to make the setWellSelection call synchronous somehow so that it has a chance to populate the dropdown select box before the rest of the render function executes and the template is displayed.
I do not know how to do that.
You can modify the html returned from your template before rendering it to the screen.
You could modify the html directly cause it's only string. This way you will have a nice performance solution but will be hard and painful to maintain.
Another way is to turn the html string to jquery object and modify it which I think is a better way, even though it may be slow. Later you can grab the updated html from jquery object and render to screen.
My front-end structure is like below:
<div id='item-list'>
# List of items to be replaced every time
</div>
<form>
<submit/>
</form>
The idea is that, every time when the submit button is clicked, my JS would send AJAX request, and the server would return an HTML partial for the item-list, and in my front-end, the item-list would be replaced with the ajax return.
However, since there're also some use of UJS in my item-list, the bindings no longer works after the replacement.
I believe it's the problem that the UJS code didn't execute when the replacement happens. I want to ask how to force the execution of UJS code?
Thanks a lot
You'll need to delegate your event bindings from an element which is always going to be present on your page (typically document):
$(document).on("submit", ".element", function(){
//stuff
});
The problem you have is that Javascript only works with elements in the actual DOM. It doesn't, nor can it work with, elements which are appended after the DOM has been loaded
This means you have to bind the javascript events to elements which will always be present in the DOM, and delegate from them
--
That's the best I can do with what you've sent so far - if you give more context, I'll be able to provide a richer answer
So I have a new Rails 4 App using foundation and I started to integrate DataTables today and ran into one minor setback after setting it up to page using ajax calls.
When I click a link from one page (home in this instance) that sends me to a page that contains the datatables, the tables render without any entries or search box or pagination etc. However, if I refresh my browser, the page will fully refresh and the ajax call is made and the the table populates correctly.
After looking at the network traffic, I'm seeing that after clicking the link the response is 304: Not Modified. Since none of the other requests for the JS and CSS and etc, I'm assuming that the JS doesn't reload and make the proper ('#tasks').dataTable({...}) call.
Also, one thing to note is that the table is residing within a partial 'tasks_index.html.haml'.
One thing I did remember however was that I was still using the Turbolinks gem. I tried disabling it to see if that would fix my problem and surprisingly enough, it did.
So what would cause Turbolinks to prevent normal javascript to load on the page? Is there any way to force turbolinks to always load certain pages? Am I better off not even using Turbolinks?
I guess you are using the $(document).ready event to initialize the datatables. When using turbolinks when you click a link this event won't fire because turbolinks loads the page itself. So you should use the document page:change event instead. See here: http://guides.rubyonrails.org/working_with_javascript_in_rails.html#page-change-events
Just like lunr said, you have to put $(document).on "turbolinks:load", -> in your .coffee file
I successfully used the following CoffeeScript code to make DataTables work correctly on Rails 5 / Turbolinks 5.
If you use this script, you will no longer have the problem where the DataTables wrapper reloads after you hit the back button on your browser.
Please note that I also am using the turbolinks-compatibility script.
I'm hopeful this will help someone else who is Googling / struggling with this like I was.
TurboLinks is great for speed ... but it makes loading JavaScript a pain.
$(document).on 'turbolinks:load', ->
tableElementIds = [
'### TABLE ID HERE ###'
]
i = 0
while i < tableElementIds.length
tableElementId = tableElementIds[i]
if $.isEmptyObject($.find(tableElementId))
i++
continue
table = undefined
if $.fn.DataTable.isDataTable(tableElementId)
table = $(tableElementId).DataTable()
else
table = $(tableElementId).DataTable(### OPTIONS HERE ###)
document.addEventListener 'turbolinks:before-cache', ->
table.destroy()
return
i++
return
In a Rails 3.2 app I have a javascript function that is triggered by the presence of a DOM element with class "trigger". (this function adds UI elements).
This works perfectly, except in partials that are rendered by ajax calls.
For example in an index view, when the page is initially rendered the function is correctly called and the UI elements rendered.
If the user then filters or paginates or otherwise interacts with the index via ajax, the function is not called and the UI elements are not applied when the partial is re-rendered via the ajax call.
So, how can I make javascript aware of elements that are rendered via ajax calls?
I think you should use jQuery.on() method.
eg
$("#content").on("click", "input[type='checkbox']", function(event){
// do some stuff
});
Seems this question has been asked before, but I was not using the correct search terms.
In case anyone else stumbles across this, the answer is...
Adding $('.switch')['bootstrapSwitch'](); to the end of your some_action.js.erb file should do the trick....
And the full question is
bootstrap-switch functionality does not load when I re-render a partial with "respond_do"
I'm using Gmap4Rails in the body of a form that is loaded via Ajax. There are custom fields in the form and some of them may be location pickers that I have working on a non-Ajax version of the form.
With the Ajax version of the form, I'm getting "Gmaps.my_map_id" undefined errors.
In the non-Ajax version of the form, I call Gmaps.loadMaps via JavaScript in the HTML page head for "window.onload" as is the normal practice with Gmaps4Rails.
However, this won't work in the context of Ajax, as the map(s) haven't been defined at window.onload time.
In my form, I also define a callback per Gmaps map object. This is what seems to be failing with the "undefined" error, even when I do a "Gmaps.loadMaps();" script directly before the first callback is defined in the code that is loaded by Ajax.
Basically it goes like this in code order:
in a loop, gmaps4rails partial is called to output each map custom field
after that loop finishes, Gmaps.loadMaps() is called once
in another loop, each Gmaps map object has the JS for its callback added
Any suggestions on how to get this working?
UPDATE: possibly only partly correct (i.e. I did have the problem that was outlined here, but calling Gmaps.loadMaps() still doesn't work).
2nd Update: I have had to alter the definition of the load_... to be on the Gmaps object and then alter Gmaps.loadMaps function accordingly. I've put in a pull request to the project at https://github.com/apneadiving/Google-Maps-for-Rails/pull/94.
The Gmaps.loadMaps() call wasn't the issue. So an alternative isn't necessary. The thing that was tripping me up is that in the partial enable_js was being called as false and the JavaScript that declares the new instance of the Gmaps4RailsGoogle and the function for loading it was not being called.
I have a custom version of the partial and in my case, even when enable_js (I interpret as "don't load javascript library files" for my app) is false, I still do the JavaScript that declares the new Gmaps4RailsGoogle instance and defines the load_... function.
That being said, the load_... function appears to be not working for me. It comes back with the following in my case:
TypeError: 'undefined' is not a function (evaluating 'window"load_" + key')
When I call the load_... function directly from the console (rather than the Gmaps.loadMaps call), I get a similar error:
"'undefined' is not a function (evaluating 'this.load_...()')"
Perhaps having to do with not having any markers declared? Any hints on that problem appreciated.
If I step through the steps in the load... function, the first bit that throws an error is .initialize(). Still investigating.