jQuery on() click event handler with dynamic data crashing - event-handling

Here's a simplified example of what I'm trying to achieve: http://jsfiddle.net/easLc/
HTML
<div class="bar">
<div class="apple"> apple</div>
<div class="banana"> banana</div>
<div class="citrus"> citrus </div>
</div>
jQuery
function showAlert(event) {
inventory = event.data.inventory;
alert(inventory);
}
fruits = ["apple", "banana", "citrus"];
inventory = [13, 45, 99];
for (i in fruits) {
$(".bar ."+fruits[i]).on("click", {inventory:inventory[i]},showAlert);
}
The inventory data I'm passing to the handler is dynamic, not static like the example. I'm getting the inventory data from asynchronous calls. After each time the inventory data is updated, I want to pass this data to the handler instead of have the handler get that information again.
What I'm noticing is on some clicks, the handler (I think) is crashing my browser. Am I creating too many handlers inadvertently? How do I see what handlers were created? Or what happens during the click event? I tried adding some console.log to the handler but I don't see them in the console.
Thanks!

Try
$(".bar ."+fruits[i]).off('click',showAlert).on("click", {inventory:inventory[i]},showAlert);
This will remove the previously bound event and rebind it... But it is hard to determine if it is the real source of the problem. You can add a console.log('text') in showAlert to see if it is being called more than once.

You can prevent multiple bindings by adding some sort of data to the element once it's been bound (a clean way would be a class, but meta-data may be preferred by standards):
$(".bar ." + fruits[i]).not(".bound").on('click', {...}).addClass('bound');

Related

Prevent re-targeting of events on LWC

Not able to get the event's original source on LWC.
Hi,
We are migrating an Aura component to LWC. We have a USE CASE, is being used in an iteration.
On click of , we are showing . The data in is dynamically retrieved based on record-id of .
In Aura, this was fairly simple because when fires an event, we can inject the data through method from grand parent to event.getSource().
But in LWC, the event is getting re-targeted on every parent-level bubbling. So finally event.target is returning the instead of .
Hence we are not able to inject data dynamically through event. What is the best approach for this scenario?
<!--c-todo-app>
<c-todo-item>
<div>
<!--Dynamic Iteration--Starts>
<c-todo-line-item>
<c-sub-item>
<c-todo-line-item>
<c-subitem>
--
...
...
...
--
<c-todo-line-item>
<c-subitem>
<!--Dynamic Iteration--Ends>
</div>
</c-todo-item>
Event.target OR event.currentTarget should give the source component but instead gives the top-most component below the handling component. In above example- event is fired in and handled in . Component returned is BUT we need

How can I create a Google Tag Manager rule which fires based on the presence of a DOM element with no ID?

I'm working on a client's ecommerce website where, when somebody signs up successfully to the site, a success message () is displayed within an unordered list element ().
I would like to create a Google Tag Manager Rule which fires when this success message has loaded on the page, but can't figure out how - and would love your help if you can spare a min!
Based on my readying (primarily Simo Ahava - http://www.simoahava.com/analytics/macro-guide-google-tag-manager/) I've tried creating a DOM Element macro where the ElementID is "success-msg", and then using that to create the following rule:
{{url}} - ends with - /artistsignup/index/index
{{success message}} - greater than - 0
{{event}}} - equals - gtm.load
However this doesn't seem to be working.
Any advice would be very much appreciated, thank you so much!
<div class="col-main">
<ul class="messages">
<li class="success-msg">
<ul>
<li>
<span>Thank you for signing up.</span>
</li>
</ul>
Alex
I have to do this a lot for my clients and the following seems to work for me. NOTICE: This solution utilizes jQuery.
The idea is that you want to run a script that checks to see if the success message is visible, when it becomes visible, push a dataLayer event to the GTM (Google Tag Manager).
Step One, create a custom HTML tag in the GTM console that fires a dataLayer event when the success message becomes visible:
<script type="text/javascript">
(function(){
try{
// Set a variable to the setInterval method so it can be cleared.
var checkSuccess = setInterval(function(){
// Check if the success message exists.
if($('span:contains(Thank you for signing up)').length !== 0){
// Check if the success message is visible.
if($('span:contains(Thank you for signing up)').is(':visible')){
// Push the success event to the GTM's dataLayer.
dataLayer.push({'event' : 'signUpSuccess'});
// Terminate the interval upon success.
clearInterval(checkSuccess);
}
}
},500);
}catch(e){
// Uncomment to view errors.
// console.log('GTM Error: ' + e);
}
})();
</script>
Notice that I didn't use document ready. That's because this tag should only fire upon event = gtm.load in GTM, which will serve the same purpose. Specifically, the following firing rule should be appropriate
{{url}} - ends with - /artistsignup/index/index
{{event}}} - equals - gtm.load
Finally, any tracking tags that you want to fire when the success message appears should have the following rule:
{{event}} - equals - signUpSuccess
Final note, if you can't use jQuery for this, then just replace the jQuery selectors with a pure JavaScript selector.
Thanks

How do I auto-bind properties in nested repeat-templates in polymer?

I'm trying to make a simple extension of the table element. Where you can click a td, then it becomes editable, and when you edit the data it gets automatically persisted via a REST service.
Here's what I got so far
As you can see, you can click the td's and edit them, but the data does not get persisted to the other side (which is firebase in this case). That's because the data in the td's aren't bound anymore to the data-property from which they came. Can somebody tell me how I can bind them to that property again? Or any other way I can persist the data to the correct row and key?
As far as I know contenteditable change events are not supported by polymer.
You could use the onkeys to update the model manually.
In a on-* handler, you can access the named model instance using: e.target.templateInstance.model.:
<polymer-element name="x-foo">
<template>
<template repeat="{{user in users}}">
<div on-click="{{clickHandler}}">{{user.name}}</div>
</template>
</template>
<script>
Polymer('x-foo', {
clickHandler: function(e, detail, sender) {
console.log(sender.templateInstance.model.user.name);
}
});
</script>
</polymer-element>
Sevesta told me that it could only be done manually, so I gave every td extra data-attributes so I could identify them and then at the stopEditing() function I update the models manually.
See here.

Knockout.js: Multiple ViewModel bindings on a page or a part of a page

I am wondering if it is possible to use Knockout.js's ko.applyBindings() multiple times to bind different ViewModels to one part of a page. For example, let's say I had this:
<div id="foo">...</div>
...
ko.applyBindings(new PageViewModel());
ko.applyBindings(new PartialViewModel(), $('#foo')[0]);
I am now applying two ViewModel bindings to <div id="foo>. Is this legal?
You do not want to call ko.applyBindings multiple times on the same elements. Best case, the elements will be doing more work than necessary when updating, worse case you will have multiple event handlers firing for the same element.
There are several options for handling this type of thing that are detailed here: Example of knockoutjs pattern for multi-view applications
If you really need an "island" in the middle of your content that you want to call apply bindings on later, then you can use the technique described here: http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html
This is a common road block that comes when implementing JqueryMobile-SPA.
The method : ko.applyBindings(viewmode,root dom element) accepts two arguments. The second argument comes helpful when you have multiple VM's in your page.
for example :
ko.applyBindings(model1, document.getElementById("view1"));
ko.applyBindings(model2, document.getElementById("view2"));
where view1 and view2 are the root dom element for that model. For a JqueryMobile-SPA this will be the page ids for corresponding model.
The best way to do this would be use the "with" binding construct in the div that you want the partial view model to be bound. You can find it in this fiddle
<div data-bind="with: model">
<p data-bind="text: name"></p>
</div>
<div data-bind="with: anothermodel">
<p data-bind="text: name"></p>
</div>​
var model = {
name: ko.observable('somename'),
}
var anothermodel = {
name: ko.observable('someanothername'),
}
ko.applyBindings(model);​
Also check out the "with" binding documentation on the Knockout site, to look at an AJAX callback - partial binding scenario.
My english is very bad.... =)
I use Sammy to load partial views, and Knockout to bind the Model, I try use ko.cleanNode but clean all my bindings, all DOM nodes has changed when has a bind, a property __ko__ is aggregated, then i removed that property with this code, and works !!, '#main' is my node.
var dom = dom || $("#main")[0];
for (var i in dom) {
if (i.substr(0, 6) == "__ko__") {
delete (dom[i]);
break;
}
}
after use Ggle translator:
I use Sammy for the load of partial views, and Knockout for the bind the Model, I try to use ko.cleanNode but clean all my bindings, all DOM nodes has changed when they has a bind, a property ko is aggregated, then i removed that property with this code, and works !!, '#main' is my node.

delete item from a dojo.store.jsonrest

I started with this tutorial http://dojotoolkit.org/documentation/tutorials/1.6/store_driven_tree/
after setting up my ServerSide Restfull Service everything is working so far. I made a contextmenu for the tree by:
<ul dojoType="dijit.Menu" id="contextMenu" style="display: none;">
<li dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconDelete" onclick="pages.remove(tn.item.id);">delete page</li>
</ul>
<script type="dojo/connect">
var menu = dijit.byId("contextMenu");
menu.bindDomNode(this.domNode);
dojo.connect(menu, "_openMyself", this, function(e){
// get a hold of, and log out, the tree node that was the source of this open event
tn = dijit.getEnclosingWidget(e.target);
// contrived condition: disable all menu items except the "New Page" item
dojo.forEach(menu.getChildren(), function(child){
if(child.label != "Neue Seite")
{
child.set('disabled', typeof tn.item == 'undefined');
}
});
});
</script>
Now I know on wich node the user made the right click for the contextmenu and delete it with "pages.remove(tn.item.id);" from the Database. To notify the tree I´m overriding the remove function:
remove: function(objectId){
this.onDelete({id: objectId});
return dojo.store.JsonRest.prototype.remove.apply(this, arguments);
}
Everything works as expected but if im now doing some other things with the items in the tree like drag n drop an item to the root i was deleting a child before. The tree isn't showing it correctly anymore. I think the remove method of the store only sends the DELETE query to the Server but don't removes the item from the store. How can i get the array of the items in store to check and maybe to delete items?
The dijit.Tree is a presentation of an underlying dojo.data model, and any changes that you want to make to the tree really need to be done to the underlying data store. See the description here: http://dojotoolkit.org/reference-guide/dijit/Tree.html#dijit-tree So, instead of overriding the remove function, you should instead use the dojo.data API to modify the store, and then rerender the tree to reflect the changes. The best source for looking at the various methods available is in the dojo nightly files. Specifically, the dojo.data files are here: http://archive.dojotoolkit.org/nightly/dojotoolkit/dojo/data/
var item = tree.fetchItemByIdentity("selectedItem"); //find the item you want to remove
store.deleteItem(item); //delete the item from the data store
store.save(); //save the change made to the store