Rails check partial is fully loaded following ajax call - javascript

I render a partial after an ajax call:
show.js.erb
$("#notice_feed").html("<%=j render 'shared/notice_feed' %>")
_notice_feed.html.erb
<ol class="notices" id="notice_list">
<%= render #notices %>
</ol>
This ends up rendering a list of #notices. The names of each notice are listed on the right and I have some jquery to scroll down to the relevant rendered #notice when you click on the name:
name.on('click', function() {
$("#absolute-div").animate({scrollTop: $('#notice_' + this.className).offset().top -200 }, 500);
});
When you click on the name it correctly scrolls down, but only sometimes stops scrolling on the correct #notice, and gets nowhere near for other #notices. I suspect the problem is that the jquery is called before the whole partial list has finished rendering. I've tried surrounding the javascript with
$(window).on("load", function() {
...
};
but this doesn't fire, presumably because it already fired when the original page was loaded.
How do I check that a partial following an ajax call has fully loaded using jquery?
Or is there a better way to identify a div and scroll to it accurately?

You can do this in two ways:
Rails way:
Make a method on js for call the animate scroll something like that:
name.on('click', function() {
scrolling_to(this.className);
});
function scrollin_to(name){
$("#absolute-div").animate({scrollTop: $('#notice_' + name).offset().top -200 }, 500);
}
Then, in show.js.erb do that:
scrolling_to(#notice_show.name);
Js way:
Use ajax to call to the rails route:
jQuery.ajax({
type: 'get',
url: 'your url here',
dataType: 'json',
cache: false,
success: function(data, textStatus){
$("#notice_feed").html(data.msg);
$("#absolute-div").animate({scrollTop: $('#notice_' + data.name).offset().top -200 }, 500);
}
});
Rails show method:
def show
data ={
msg: #notice_feed
name: #notice_feed.name
}
render json: data;
end

Solved it. I changed .offset() to .position(). Now it works beautifully.
name.on('click', function() {
$("#absolute-div").animate({scrollTop: $('#notice_' + this.className).position().top -200 }, 500);
});
I needed the position of the #notices relative to the parent, not the document (jQuery here).

Related

How to use afterRender and rebuild from fullpage.js

I've read the documentation regarding afterRender from the fullpage.js github page. In my site I have content that is generated by AJAX in a particular div.
Example below
$("#fullpage").fullpage({
afterRender: {
// I don't know what to put here
}
});
$("#btn-generate-content").on("click", function() {
// Target the div
$.ajax({
url: "get_topic_content.php",
dataType: "json",
success: function(data) {
// Place the data in the div
}
});
});
With the code above, I'm generating a long paragraph and placing it into a div. Now I want my site to resize accordingly to the generated paragraph. How can I use reBuild() on the afterRender to target this particular div when it has finished rendering the content.
After get ajax content you should use $.fn.fullpage.rebuild() in a callback.
I don't see an action of placing html content.
It should be done in success function, and then you should call rebuild function.

$(document).foundation(); not working

I try to get my elements, that I load via ajax back to work but when I try to reinitialize the events on them, it simply doesn't work.
I tried to insert $(document).foundation(); on different places in my code but nope :(
Here an example:
$.ajax({
url: 'dashboard/ajax/links/get',
method: 'post',
data: {
_token: $('input[name=_token]').val()
},
success: function(data) {
$('.links-container').html(data);
$(document).foundation();
}
});
Any ideas?
Update
Another example
// open edit link modal
$('.item-link-edit').on('click',function(e){
e.preventDefault();
// get item id
var id = getItemId(this);
// open modal and load content
$('#edit-link-modal').foundation('reveal','open',{
url: 'dashboard/ajax/links/modals/edit',
data: {
id: id
},
success: function() {
setTimeout(function(){
$(document).foundation();
console.log('reinit');
},1000);
}
});
});
still not working :/
You need to use reflow if you add new content to the DOM.
$(document).foundation('reflow');
Reflow will make Foundation check the DOM for any elements and re-apply any listeners to them. If you dont want to reflow everything you can specify the module you want to re-apply;
$(document).foundation('orbit', 'reflow'); // orbit, for an example
Further documentation can be found here:
http://foundation.zurb.com/docs/javascript.html

getting the loading icon to appear while using the jquery modal popup

I have been trying to get the loading gif to replace the cursor while I am updating the database or loading. It does work when my tabs are loading but it doesn't when I am saving from the jQuery modal popup.
when I debug and look at the rendered html it tells me it is displaying right before it makes the call style="display:block;" when I let it complete the save it switches back to style="display:none;" The below code is just a taste, sorry I can't transfer the actual code from the development network to here. Since I am using these popups for every edit in a huge application, I really would like to get the loading gif showing.
//using jquery to start and stop with ajax
var $loading = $('#waiting').hide();
$(document)
.ajaxStart(function () {
$loading.show();
})
.ajaxStop(function () {
$loading.hide();
});
//my div
<div id="waiting" class="loading-img" style="display:none;"
$("#somePopup").dialog({
autoOpen:false,
height: 'auto',
width: 900,
buttons: { Save: ....
// you get the idea
$ajax({
type:"post",
url: "some procedure",
dataType: "json",
data: DTOvar,
contentType: "application/json",
async: false,
success: function(data){
//refresh main screen and close popup
error : function(errorstuff){
//handle error
}
});
It won't work since you specified "async: false", signalling the browser to use the same ui thread. ajaxStart/ajaxStop methods will never have a chance to run. You should most likely remote the sync option to achieve what you need.

jquery select2 after ajax not working anymore

I have a simple select2 control on my site placed in a div. When the site loads, everything works fine. However, if the html content of the div "simpleDiv", where the Select2 is placed, is loaded with Ajax, the Select2 is not showing the results anymore when triggered.
That means, in this case the Select2 data is got from the Server, but never shown in the Select2.
And this all happens just when the "simpleDiv" html content is loaded with Ajax. Otherwise, everything works fine.
Can anyone help, please?
<div id='simpleDiv'>
<input type="hidden" id="MedikamentID" name="MedikamentID" class="fixed-width4" />
</div>
<script>
$('#MedikamentID').select2({
placeholder: "[Medikament]",
allowClear: true,
minimumInputLength: 2,
ajax: {
url: "/Medikament/List",
dataType: 'json',
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data };
}
}
});
</script>
Whenever you change things using .html() or .innerHTML, essentially, the DOM gets reconstructed and all the javascript events and properties attached to them is lost. But the fix is simple. Just call Select 2 again after you finished inserting the new HTML. So something like:
$.ajax("example.php").done(function(data){
$("#simpleDiv").html(data)
$("#MedikamentID").select2(...) //rebuild select2
})
I attached a jsfiddle to illustrate this:
http://jsfiddle.net/HT3rP/1/
If I got your question correct, you may be having a similar problem related to this stackoverflow problem
You could try something like this
$(document).on("ready", "#MedikamentID", function () {
$(this).select2({
// options go here
});
});

Why does $.load( handler(eventObject) ) not work for data returned from server after Ajax request, trying to make it wait for all images to load

I need to keep displaying the loading gif until all images
in the returned data (html) have been finished loading.
The data and everything is returned properly, but the .live('load', function() {})
is never executed, have tried without the .live as well. The contents of #ContentBody
just get replaced with the returned html data (#LoadingLayer disappears too of course) and I can see images loading as usual.
<script type="text/javascript">
$("#RightLink").click(function (event) {
event.preventDefault();
var tourl = $(this).attr('data-ajax-url');
$.ajax({
type: "POST",
url: tourl,
dataType: "html",
async: true,
beforeSend: function () {
$("#LoadingLayer").show(); //show layer with image loading gif
$('#ColumnContainer').hide();
},
success: function (data) {
$('#ContentBody').html(data).live('load', function () { $("#LoadingLayer").hide(); });
}
});
});
</script>
HTML layout:
<body>
<div id="ContentBody">
<a id="RightLink" href="/store/ContentBodyGenerator" />
<div id="LoadingLayer"><img src="loading.gif" /></div>
<div id="ColumnContainer">... Main contents, lots of images here</div>
</div>
</body>
Why don't you just hide #LoadingLayer directly?
$('#ContentBody').html(data);
$("#LoadingLayer").hide();
Edit:
I misread your question, I don't think there is an easy way to detect that all images have been loaded. I suggest you try the waitForImages plugin.
Try changing the contents of the "success" function to this...
$('#ContentBody').html(data).live('load', function () {
var imgcount = $(this).find("img").length;
$(this).find("img").one("load", function() {
imgcount--;
if (imgcount == 0) {
$("#LoadingLayer").hide();
}
}).each(function() {
if (this.complete) $(this).load();
});
});
It waits till html(data) is loaded and then gets an image count. It then adds an event handler to each of the images to decrement the image count when the image is loaded. The one("load" code means only allows the following code to run once, and the each code basically says "if it's already loaded (as per cached images) then run the load event".
Once the image count is 0 it hides the loading layer.
Without a URL where I can run this through the console I can't be 100% sure it's accurate, so it may need a fiddle about. If you get stuck give us a shout.
Try binding the load event to the images. Keep track of how many have loaded, and remove the loading layer only after they've all loaded. This is untested code but should give you an idea:
success:function(data){
// Set the content
$('#ContentBody').html(data);
// How many images do we have?
var images = $('#ContentBody img'),
leftToLoad = images.size();
// Listen for load event *FOR IMAGES*
images.bind('load', function (){
// Hey look we loaded one, was that the last one?
if(--leftToLoad === 0){
// Yep, we're done
$("#LoadingLayer").hide();
}
});
}
If you'd rather use live than handling in the ajax callback, do this in your $(document).ready callback:
$('#ContentBody img').live('load', function(){...});
Should do the trick.
Cheers

Categories