Call method when dynamic element is in DOM - javascript

I use $http service to get data and generate DOM elements.
How can I in jQuery/AngularJS call a method (example .slideToggle()) on dynamic element? I need to do this when page is loaded (not on click event etc.).
To do this one $('#test').slideToggle() (#test is generated element) i need use timeout.

It's difficult to know for sure from your description, but if you're creating the element from data you retrieve remotely, you should ensure that element's creation/insertion are completed before you attempt to scroll to it.
The following code is an example of how you may do this:
$http({
method: 'GET',
url: '/someUrl'
})
.then(createAndInsertYourElement)
.then(scrollToElem);
function createAndInsertYourElement(data) {
var $elem = $('<div id="test">' + data.whateva + '</div>');
$('#someElement').append($elem);
return $elem;
}
function scrollToElem($elem) {
$elem.slideToggle();
}
Note the .thens. These are an option because Angular's $http returns a promise. If you're not familiar with promises, yet, they are awesome, and you should check 'em out: http://www.dwmkerr.com/promises-in-angularjs-the-definitive-guide/

Related

Ajax call in "for" loops skips odd/even iterations

If I am here asking it is because we are stuck on something that we do not know how to solve. I must admit, we already searched in StackOverflow and search engines about a solution.. but we didn't manage to implement it / solve the problem.
I am trying to create a JavaScript function that:
detects in my html page all the occurrences of an html tag: <alias>
replaces its content with the result of an Ajax call (sending the
content of the tag to the Ajax.php page) + localStorage management
at the end unwraps it from <alias> tag and leaves the content returned from ajax call
the only problem is that in both cases it skips some iterations.
We have made some researches and it seems that the "problem" is that Ajax is asynchronous, so it does not wait for the response before going on with the process. We even saw that "async: false" is not a good solution.
I leave the part of my script that is interested with some brief descriptions
// includes an icon in the page to display the correct change
function multilingual(msg,i) {
// code
}
// function to make an ajax call or a "cache call" if value is in localStorage for a variable
function sendRequest(o) {
console.log(o.variab+': running sendRequest function');
// check if value for that variable is stored and if stored for more than 1 hour
if(window.localStorage && window.localStorage.getItem(o.variab) && window.localStorage.getItem(o.variab+'_exp') > +new Date - 60*60*1000) {
console.log(o.variab+': value from localStorage');
// replace <alias> content with cached value
var cached = window.localStorage.getItem(o.variab);
elements[o.counter].innerHTML = cached;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(window.localStorage.getItem(o.variab),o.counter);
} else {
console.log(o.variab+': starting ajax call');
// not stored yet or older than a month
console.log('variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language);
$.ajax({
type: 'POST',
url: my_ajax_url,
data: 'variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language,
success: function(msg){
// ajax call, storing new value and expiration + replace <alias> inner html with new value
window.localStorage.setItem(o.variab, msg);
var content = window.localStorage.getItem(o.variab);
window.localStorage.setItem(o.variab+'_exp', +new Date);
console.log(o.variab+': replacement from ajax call');
elements[o.counter].innerHTML = content;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(msg,o.counter);
},
error: function(msg){
console.warn('an error occured during ajax call');
}
});
}
};
// loop for each <alias> element found
//initial settings
var elements = document.body.getElementsByTagName('alias'),
elem_n = elements.length,
counter = 0;
var i = 0;
for(; i < elem_n;i++) {
var flag = 0;
console.info('var i='+i+' - Now working on '+elements[i].innerHTML);
sendRequest({
variab : elements[i].innerHTML,
api_key : settings.api_key,
language : default_lang,
counter : i
});
$(elements[i]).contents().unwrap().parent();
console.log(elements[i].innerHTML+': wrap removed');
}
I hope that some of you may provide me some valid solutions and/or examples, because we are stuck on this problem :(
From our test, when the value is from cache, the 1st/3rd/5th ... values are replaced correctly
when the value is from ajax the 2nd/4th .. values are replaced
Thanks in advance for your help :)
Your elements array is a live NodeList. When you unwrap things in those <alias> tags, the element disappears from the list. So, you're looking at element 0, and you do the ajax call, and then you get rid of the <alias> tag around the contents. At that instant, element[0] becomes what used to be element[1]. However, your loop increments i, so you skip the new element[0].
There's no reason to use .getElementsByTagName() anyway; you're using jQuery, so use it consistently:
var elements = $("alias");
That'll give you a jQuery object that will (mostly) work like an array, so the rest of your code won't have to change much, if at all.
To solve issues like this in the past, I've done something like the code below, you actually send the target along with the function running the AJAX call, and don't use any global variables because those may change as the for loop runs. Try passing in everything you'll use in the parameters of the function, including the target like I've done:
function loadContent(target, info) {
//ajax call
//on success replace target with new data;
}
$('alias').each(function(){
loadContent($(this), info)
});

ajax loading of search results

I have setup a search funtionality that will search in an XSLT file. This works flawlessly but I have a little trouble returning the search results dynamically with ajax.
This is my JS:
var SearchHandler = function(frm) {
frm = $(frm);
var data = frm.find(".search-field").val();
$.ajax({
method: 'GET',
url: '/',
data: { query: data },
dataType: 'xml',
success: SearchSuccessHandler,
error: SearchSuccessHandler
});
};
var SearchSuccessHandler = function(html) {
};
What I want is the SearchSuccessHandler to dynamically load the search result from index.php?query=searchword
I just can't seem to figure out the right way to handle it.
Based on your comment:
Bah.. Sorry... The ajax call will return some new html based on the
query ... I want the existing html to be replaced I have tried
$('body').html(html.responseText); but then I cannot search again
because javascript is not loaded correctly
It's not the AJAX which is the issue but rather event delegation
When you bind a function to an element directly like this:
$('.my-element').on('whatever', function() { ... })
the handler will work as long as the element exists however if you replace the contents of the entire body you'll run into trouble as your original .my-element no longer exists.
You can overcome that by using event delegation to make sure your function keeps searching e.g.
$(body).on('whatever', '.my-element', function() { ... })
This basically says: "If I click on body and the target is .my-element then execute this function"
Instead of a directly bound handler which says: "If I click on this specific element then execute this function"
the body will always exist and therefore you'll always be able to delegate down from the body but if you can do it on some more specific element that would obviously be better since then you won't have an onclick handler on the entire body.
I think this is what your issue is since you're replacing the entire body.
Try this
success:function(data) {
// do your stuff here
}
Of course, you need to be sure your function is returning some values.
To make it easier for your, encode the values as json on your index.php
return json_encode($values)
Then, inside your success function, just parse it with eval()

jQuery autocomplete + data attributes returned uiAutocomplete in the result

I am trying to use the autocomplete from jQueryUI. I need to do a data call to the backend, but other than the value from request.term there are other parameters i need to pass as well, so instead of using some other means if passing the additional data, i thought of using the data- attributes to do it.
var input = $(document.createElement("input"));
mydata.each(function() {
input.attr('data-'+this.nodeName, this.innerHTML);
});
So when i build my <input> i also put a brunch of data- attributes in there, the idea is that when i need to do the autocomplete call, i should be able to just do input.data() and grab everything i need.
However, i am getting some weird behavior from jQuery's .data() call.
input.autocomplete({
source: function(req, resp) {
$.ajax({
url: $(this.element).attr('action'),
dataType : 'json',
data: $(this.element).data(),
cache : false
}).done(function(resp) {
console.log(resp);
}).fail(function() {
alert("failed");
});
},
...
In the above code, when i do $(this.element).data(), it does indeed returned my all the attributes that i defined, but it also included something else, such as the uiAutocomplete object...
I thought the .data call is supposed to return only the items with prefix data-? What is the best way to grab the data- attributes?
This is because jQuery uses data attribute to store plugins namespace data in it, the more plugin used in it, the more data namespaces you will get. This is not weird, this is how jQuery works. As it is said here -
Calling jQuery.data( element ) retrieves all of the element's
associated values as a JavaScript object. Note that jQuery itself uses
this method to store data for internal use, such as event handlers, so
do not assume that it contains only data that your own code has
stored.
Reference:
https://api.jquery.com/jQuery.data/
As far as your solution, you should namespace your data if you wish to retrieve it later. Something like -
input.data('mydata', {name:'test'});
and then get it by -
var data = input.data('mydata');
In my observation the data method were returning the values set as below
1)setting the values
$(".autoCompleteInput").data("attribute1", "value1");
$(".autoCompleteInput").data("attribute2", "value2");
$(".autoCompleteInput").data("attribute3", 4);
$(".autoCompleteInput").data("attribute4", 5);
2) Getting the values
var datas = $(".autoCompleteInput").data();
3)assigning the values to other control
var stringData = JSON.stringify(datas);
$(".DataDisplay").val(stringData );
http://api.jquery.com/data/
Creating an Autocomplete sample
1)Created another page that returns a string of values used for autocomplete.
2)Made a Ajax request and retrieved the values into a local Array.
3)used the Array of values to Populating the AutoComplete.
4)incase of some widgets Make sure you are including the necessary jquery library and some related css into your page.
$(document).ready(function () {
$.ajax({
url: "AutoCompleteDataProvider.cshtml",
success: function (data) {
var autoCompleteValue = data.split(',');
$(".autoCompleteInput").autocomplete({
source: autoCompleteValue
});
},
error: function (textStatus) {
alert(textStatus);
}
});
});

Mootools appending html after an ajax request

I have an ajax call that looks like this,
$('campaignType').addEvent('change', function(){
alert($('campaignType').value);
var request = new Request({
method: 'get',
url: '/admin/admin_' + $('campaignType').value + '.php',
onRequest:function() {
alert('Request has been made, please be patient')
},
onComplete:function(response) {
$('campaignForm').append(response);
}
}).send();
});
Essentially what happens is depending on what the value of `$('campaignType') some HTML is returned from another file, however I cannot seem to get the HTML to append on to my container. Any one care to give me some advice?
Thanks
Dimitar's solution is close but is a bad solution as it recreates the whole element contents and destroys attached event handlers. A better solution would be:
Element.implement({
append: function(newhtml) {
return this.adopt(new Element('div', {html: newhtml}).getChildren());
}
});
this is actually what Request.HTML internally does.
.append is not a valid element prototype in mootools.
if you want to append html to an existing one, then you can either MAKE .append valid by defining in your site lib/core bit (I would consider this if you use it a lot):
Element.implement({
append: function(newhtml) {
// silly name, does not say to me you are appending html. rename to appendHTML
return this.set("html", this.get("html") + newhtml);
}
});
or in your onComplete do:
var cf = $('campaignForm');
cf.set("html", cf.get("html") + this.response.text);
have fun :)
If you're using mootools 1.2.4 you can change Request to Request.HTML and use append option. (Not sure that append option was in older versions)
$('campaignType').addEvent('change', function(){
new Request.HTML({
method: 'get',
url: '/admin/admin_' + $('campaignType').value + '.php',
append: $('campaignForm')
}).send();
});
I think you like to use onSuccess instead of onComplete

Using domready for AJAX calls

Is there a way to know that the elements are on a document before I try to access them with JQuery?
Code Snippet:
var s = new AjaxCall(someurl);
s.oncomplete = function(response) {
var container = $('container_id');
container.innerHTML = response;
var ul = $('some_id'); }
The response is some HTML returned by the Ajax call.
This response updates the contents of a div and then I access an element that was created by the innerHTML (the ul in the code).
If the response is large, I believe there would be times that some elements would not be rendered when I will try to access them. Does domready work for AJAX calls, and could this solve my problem?
You seem to have forgotten to use #, as it should be $('#some_id');, and not $('some_id');. I suggest instead to just use document.getElmenetById. It reads more clearly and is much more efficient than contextual-based ID matching.
var some_id = document.getElmenetById("some_id");
Regarding your question of the element "not being available," don't worry. The innerHTML setter performs a synchronous operation. If a tag with a matching ID is parsed from that, then the corresponding element will be available immediately after setting the innerHTML.
If you were using jQuery, your success function for the request would be:
$.ajax({
url: "test.html",
cache: false,
success: function(resp){
var ul = $("#containerID").html(resp).find("#ElementInRespID");
//do something with ul
}
});
This will put the result in the container, find the element you want in there and set the ul variable to it.

Categories