I have a form and I add a js file via drupal_add_js() in the init code of the module.
I see the first debug message, but I can't seem to select any items from the document. I just get the jQuery object returned.
But when I add the same line into the firebug, it works.
console.log('called => init()');
console.log(jQuery('#quiz-form').find('#edit-next'));
If you're trying to retrieve the value from your form element, try:
console.log(jQuery('#quiz-form').find('#edit-next').val());
Getting the jQuery object as return is perfectly fine as methods like find actually return a jQuery object. You should check the length of the jQuery object that you are getting as return i.e. console.log(jQuery('#quiz-form').find('#edit-next').length);. If the length is zero, then of course the elements are not being found. In that case you should make sure that your JS code is being called after the DOM is ready i.e. you should either wrap your code with jQuery(document).ready or use Drupal behaviors.
I figured it out by chance. The jQuery object was trying to find the selected object before the page was initialized.
I was thinking drupal_add_js in the init module was enough.
BUt I had to wrap the jquery code in the Dom Ready function as well... as we always are supposed to do.
Related
I created a click event in adobe launch which will capture the value of the link and send it to analytics. I have created a data element for saving the value and in my DOM I am saving value in local storage.
Local storage code:
$('.card').click(function() {
var name = $(this).text();
localStorage.setItem('productName', name);
});
My problem is when I click the first link no value got saved, but after when I click second link it saves the value of first link and on third link saves value of second link and so on. I want to save current link value in evar3 variable.
Data element:
Rule:
Set variables:
Thanks,
Harshit
I'm scratching my head a little bit about why your jQuery selector doesn't match your Rule selector, but that's probably not immediately related or relevant, considering you said you are seeing data pop, in general, so at face value, I'm going to ignore that.
But in general, it sounds like your jQuery code is getting executed after the Rule is evaluated, so it's effectively one step behind. I'm not sure there's much if anything you can do about that if you aim to keep two separate click event listeners like this.
You're going to have to restructure to have one chain off the other (which I don't think is actually feasible with jQuery > Launch as-is. Maybe if you write two separate custom code blocks with promise chaining but that kind of sidesteps Launch and IMO is over-complicating things to begin with (see below)). Better yet, merge them into a single click event listener. On that note..
Why do you have two separate click event listeners? Is the sole reason for this to pass off the link text? Because you can reference the clicked element in the Launch Rule itself.
You should be able to reference %this.innerText% in the Set Variables fields. Or you can reference this object in custom code boxes within the Rule.
IOW at face value I don't see why you need or should be creating/using that jQuery listener or pushing to local storage like that.
Update:
You commented the following:
I tried with %this.innerText% it is also not showing current values. I
am pushing the value first to local storage because my link values are
generating on runtime through an API. They are not hardcoded. I am
also trying to figure out why my rule is getting fired before my
jquery is evaluated. But when I check in console using
_satellite.getVar('Product Name'); it shows me the correct value, but in debugger console value is wrong. Can you show me the way you want
to create rule to getting it fired correctly ? Thanks,
Okay so your link values are generated runtime through an API call? Well okay now that sounds like where the (timing) issue is, and it's the same issue in principle I mentioned you prolly had between the jQuery and Launch code. Assuming you can't change this dynamic link functionality, you have two options:
1. Explicitly trigger a launch rule (direct call rule) in a callback from the API code that's generating the link values.
This is the better method, because you won't have race condition issues with your API vs. link tracking code. The biggest caveat about this method though is that it requires requires you to actively add code to the site, which may or may not be feasible for you.
I have no idea what your code for generating the link looks like, but presumably it's some ajax call and generated from the success callback. So in the callback, you'd add a line of code something like this:
_satellite.track('product_image_click', {
text : elem.innerText
});
Again, I don't know what your API code that generates the link looks like, but presumably you have within it some element object you append to or update the DOM, so for this example, I will refer to that as elem.
'product_image_click' - This is the value you use for the direct call rule identifier in the interface, e.g. :
And then _satellite.track() call also includes an object payload in 2nd argument that you can pass to the direct call rule. So in the code above, I set a property named text and give it a value of elem.innerText.
Then, within the direct call rule, where you set variables, the data you passed can be referenced from event.details object within custom code box (e.g. event.details.text), or using % syntax within the interface fields (e.g. %event.details.text%).
2. Make use of setTimeout to delay evaluating the link click.
The one advantage of this method over option #1 is that it is passive. You don't have to add code directly to your site to make it work.
However, this is the shadier option, because you don't really know how long it will take for your link to be generated. But generally speaking, if you can determine it takes on average say 250ms for the link generation API to do its thing, and you set the timeout to be called at say 300-500ms, then you will probably be okay most of the time. However, it's never a 100% guarantee.
In addition, if clicking on the link ultimately redirects the visitor to another page, then this solution will likely not work for you at all, since the browser will almost certainly have navigated before this has a chance to execute. Because of this, I normally I wouldn't even mention this as an option, but since you mentioned this link involves an API that generates the link values when clicked, I figured maybe this isn't a navigation / redirect link, so maybe this is an option you can go for, if you can't do option #1.
First, create a direct call rule the same as shown in option #1. This will be the rule that receives the link text and makes the Adobe Analytics (or whatever other marketing tag) calls.
Then, create a separate rule as a click event, similar to what you are currently trying to do (listening for the link click, based on your css selector). In this rule, you won't be setting any AA variables. Instead, add a custom js box with code like this:
var elem = this;
(function (elem) {
window.setTimeout(function() {
_satellite.track('product_image_click', {
text : elem.innerText
});
}, 500);
})(elem);
So when the rule is triggered, it will create a setTimeout callback to call the first rule, passing the link text in the payload. And.. hopefully the 500ms timeout shown in the code example is enough time for the API to do its thing. You may be able to adjust it up or down.
Rather than defining it in Data Element I would say its better to keep it directly in the Rule itself. Please try with this %this.#text%.
Let me know if this helped.
Struggling here with what would otherwise be a simple $( document ).ready().
Not sure what I'm doing wrong.
Materialize needs jquery components to be initialized on DOM ready. Finding a way to initialize components on all views is surprisingly tricky.
Here is the online DEMO
From reading the docs: this should initialize everything the sub-templates require:
Template.layout.rendered = function(){
$('ul.tabs').tabs()
}
}
However, this only works on a hard page refresh, and not with links routing the views.
So instead you would have to initialize on each template that element will be used
Template.x.rendered ...
Template.y.rendered ...
Here is the github code
BTW We've tried iron-router events:
onRun
onBeforeAction
onAfterAction
All of these seem to happen before the route's template content is present. I noticed that onBeforeAction required a call to this.next() to go on, I even tried looking for the DOM content after the next call.
I also tried rewriting our routes like this:
Router.route('someRoute', function() {
this.render('someRoute');
// look for DOM content, still not found
});
Just to be clear, the reason this is happening is because your layout is only firing the rendered hook once. When you switch routes the layout template will not be rerendered, only the templates in the yield region will be. The previous template in that region gets destroyed and the next one rerendered. This means you have to run $('ul.tabs').tabs() again for that Template as the DOM elements it contains are rerendered.
Putting that code in the rendered function of the template that uses it works because that rendered hook gets run every time that particular template gets rendered again.
A way you could get around this could be to create a Template specifically for your tabs, like a control in a way, that calls $('ul.tabs').tabs() in its own rendered function. You could then put this control on a template that needed it and pass the required arguments, like number of tabs and content for each tab etc. It's a bit of work though, and I'd only consider it if I had a really large number of templates that used the tab control.
I'm trying to use the Buttonset widget in JQuery UI. I've got the package loaded and my template renders the radio buttons fine. I have a "rendered" function to call the JQ UI routine to setup the buttonset:
Template.teamList.rendered = function () {
$("#buttonsetID").buttonset();
}
But it looks like the rendered function is being called before the template is rendered! I stick a console.log in the function and it prints out to the console before there's anything on the screen. So none of the radio buttons are set up, therefore the .buttonset() call does nothing. If I make that call in the console after the page is rendered, JQuery UI does the right thing and my button set appears.
Isn't the .rendered function supposed to be called after everything's set up? Am I doing something wrong?
Thanks!
edit:
As an example, the same thing is seen in the leaderboard example.
If you add:
Template.leaderboard.rendered = function() {
alert($('.player').length);
}
When the page is displayed, it will show 0. This makes it difficult to access the DOM items if you need to add some JQuery events or, in this case, a JQuery UI element.
rendered only works for elements which will appear in the DOM the very first time the template is added to the page. Assume that subscription data takes infinitely long to arrive, then look at the template and see which elements would appear in the default state.
Using the leaderboard example, we can't assume that players are available when the leaderboard template renders (it depends on a subscription). To target a player, you should use the rendered callback on the player template.
It's hard to generalize a strategy for when to apply jQuery plugins, but here are some ideas:
Use the rendered callback if the element will always be added in the default state (e.g. the element is hard-coded and doesn't depend on a conditional).
Use the rendered callback of the most specific child template to target that child (e.g. the player template from above).
Consider using an event handler callback to target the element if it's appearance depends on an event (e.g. a button click).
Consider using a template autorun callback to target the element if it's appearance depends on reactive state. See this question for an example.
Using jquery, I am swapping some content in a web page by use of jquery's .load() function. I want to trigger an event immediately once the content has actually been loaded, but not before and not after. I'm up for any graceful solution! Why? In this instance, I'm doing the old "fade out, swap content, fade in" approach. My problem? I want to fade back in AS SOON AS the new content is loaded.
Caveats:
Using a callback function as in $('#object').load(url, callback) triggers as soon as .load() function successfully executes (before the content is actually loaded). Useless here.
Using a timed delay for fading back in is not a graceful solution. Very "clunky", especially for those with faster Internet connectivity.
JavaScript's onload event trigger does not work, as the element that .load() is altering has already loaded into the HTML DOM.
jquery's .ready() function also does not work, as the actual element is already loaded.
I do not want to create an onload or .ready() sub-container element, because that's a workaround for what I'm actually trying, though it might be as graceful or more.
How can I fire a function when (and only when) the new .load() content is finally loaded, just like JavaScript's onload event does? Thanks much.
EDIT As it turns out, the jquery .load() function is working flawlessly, and I'm approaching this wrong.
Once the .load() function completes successfully, it calls any "callback" function included by the programmer, just like any other jquery function that accepts a callback as one of its "arguments".
The .load() function is complete once it either errors or successfully begins the HTML replacement and loading of new content, but that is IT! The content will then take however long it takes to load, but your .load call is already complete before that. Therefore, expecting the callback to run after the .load content has loaded will only disappoint you. ;)
I hope others can learn from this just as I did, including those who thought what I thought was the case. Proof: as stated in the jquery ajax .load page, the callback is executed when the request completes, not when the load completes. Eureka. Whoops. /EDIT
Try using a different method rather than load(), I would suggesting using get(). Something like this may be more useful to you...
var jqxhr = jQuery.get(url,vars);
jqxhr.success(function(data){
# This will only be called once the remote content has been loaded in
# The data will then be stored in the data param and can be used within your site
});
jqxhr.error(function(data){
# Something went wrong, never mind lets just handle it gracefully below...
});
I hope this is a solution to your problem!
For more information see http://api.jquery.com/jQuery.get/
I have quickly created this function below that may be of help to you... its not refined!
jQuery.fn.loadNewData = function() {
var object = jQuery(this);
var jqxhr = jQuery.get(arguments[0]);
// check for success
jqxhr.success(function(data) {
// load the data in
object.html(data);
});
jqxhr.error(function(){
alert('Failed to load data');
});
}
Using this you can call how similarly to how you would call the load() function.
jQuery('#object').loadNewData(url);
I think you might be misinterpreting what you are seeing. Depending on the browser you are using you won't see the new elements in the browser if you pop up an alert in the callback because it won't rerender the DOM until you cede control back to the browser. That doesn't mean you can't grab the new elements from the DOM and start fading them in. Take the following jsfiddle: http://jsfiddle.net/ttb55/8/ in Chrome it will show the first div when the second alert is up, then fade in the second div. In IE it won't show the first div when the second alert is up, this is the state I think you are in after load during the callback, but it still works once you hit ok because everything was in the DOM as promised.
Upon reading the jQuery docs pages for jQuery.get() and jQuery.load(), the callback argument is quoted as the following:
"A callback function that is executed if the request succeeds."
Let me stress the terms "request" and "succeeds". The request may succeed, but that does not mean that the content is loaded. Same problem as .load() — the functions aren't built the way I was thinking.
If I want to trigger an event once the new content finally loads, I'll need to take a different approach.
I could use the JS onload event, and trigger it by completely replacing an HTML element (having the replaced code contain an onload property). EDIT: Note that using HTML iframe elements is pretty awful, primitive, and "clunky". I just need to find a better way to trigger a function as soon as loading the new content finishes.
Also, I could use jQuery to check the .ready() state of new content, but ("AFAIK" / as far as I know) that will only work if the checked content is a new HTML element, not a preexisting HTML element whose interior content is changed. The jQuery .ready() status of any preexisting element will (AFAIK) already be shown as "ready" despite if new content is loading. Perhaps I am wrong about this, and I would like to be corrected if so.
Unless otherwise notified, this answer will be marked as the correct one. The original question was mistaken that .load() was all I needed. Cheers!
I am trying to bind an event to all dialogs that have been created on a page using the JQuery UI Dialog function (whether they have been displayed or not). I can't seem to figure out a selector that will get me there. I've tried both .ui-dialog and .ui-dialog-content without success.
Since I'm trying to make a generic method, I won't know the IDs of the dialogs that may have been created.
I'm using the following code to test. It works if I specify a dialog's id (#mydialog), but in production, I won't know these.
$("div.ui-dialog").bind("dialogclose", function(event, ui) {
window.alert("close fired");
}
Do your dialogs have a common class that you can select them with? If they all have the "ui-dialog" class then this will work:
$(".ui-dialog")
Your example of
$("div.ui-dialog")
Is asking to select all divs with a class of ui-dialog, which should probably also work as long as the class is given to a div element.
Your problem might be that you binding the dialog elements before they exist? You might want the .live() function instead so that it binds to any dialogs created at any point and not just the ones that exist when the function is called.
Posting an HTML snippet would help.
You can use this:
$(":ui-dialog").each(function(){
"enter your code here"
})