Angular - Kendo treeview checkbox change event firing multiple times - javascript

I am trying to implement the checkbox change event using angular but seeing the event firing multiple times when a checkbox is clicked.
I have created a plnkr for this, please help. Ideally it should be fired only once.
$scope.treeOptions = {
checkboxes: {
checkChildren: true
},
dataBound: function(e) {
$scope.attachChangeEvent(e);
}
};
Event change code:
$scope.attachChangeEvent = function(e) {
var dataSource = e.sender.dataSource;
// issue : change event is getting called multiple times for every click on checkbox
dataSource.bind("change", function(e) {
var selectedNodes = 0;
var checkedNodes = [];
$scope.checkedNodeIds(dataSource.view(), checkedNodes);
for (var i = 0; i < checkedNodes.length; i++) {
var nd = checkedNodes[i];
if (nd.checked) {
selectedNodes++;
}
}
// check the console - this is called multiple times for one checkbox click
console.log(selectedNodes);
});
};
Is there another event to attach to to have only one event fired after all checkboxes are updated? Or maybe there is a way to group all those 'change' events and fire just one instead?

The dataBound event is triggered multiple times because you're dealing with a hierarchical data source (each child DS triggers the event, and it bubbles up). As a result, you're binding the change handler multiple times.
You should instead bind the change event from your initTree method; snippet:
var knobj = new kendo.data.HierarchicalDataSource({
data: arrayObj
});
//setting heirarchial data to scope
$scope.treeObj = knobj;
$scope.attachChangeEvent();
(updated demo)
Alternatively, you can use the dataBound event and check e.node, which is apparently undefined for the last time dataBound is triggered (demo):
dataBound: function(e) {
if (!e.node) {
$scope.attachChangeEvent();
}
}

Related

jquery function not firing when I use datatable.fnAddData to append the HTML string

jquery function not firing when I use dataTable.fnAddData to append the HTML string.
So I have a function populateDataTable(), there are two columns I needed to render an icon instead of data from JSON.
Hence, I tried to like appending the HTML string including classes for the element in fnAddData(). But somehow it's not firing the click event on the icon.
function populateDataTable(data) {
$("#customerTable").DataTable().clear();
var length = Object.keys(data).length;
for(var i = 1; i < length+1; i++) {
var index = i - 1;
var name = data[index].name;
var queue = data[index].queue;
var expire = data[index].expire;
$('#customerTable').dataTable().fnAddData( [
i,
name,
queue,
'<td id="tb-manage-key" class="tb-manage-key"><div class="tb-btn manage-key-btn switch-view" data-hide="manageCustomers" data-title="#Resources.ManageKeys" data-target="manageKeys"><span></span></div></td>',
'<td class="tb-manage-subs"><div class="tb-btn manage-subs-btn switch-view" data-hide="manageCustomers" data-title="#Resources.ManageSubscriptions" data-target="manageSubscriptions"><span></span></div></td>',
expire,
name
]);
}}
$('.tb-btn.switch-view').on('click', function(e) {
e.preventDefault();
switchView(this);
console.log('Testing'); //not firing
});
Icon is showing, but not firing click event as it supposed to be. Attached below shows that we can see it appends the div as expected.
Solutions
Adding the click event within the populateDataTable() works.
$('#customerTable tbody').on('click', '.tb-btn.switch-view', function() {
switchView(this);
});
You can try a different syntax to listen to the click event...
$('td').on('click', '.tb-btn.switch-view', function(e) {
e.preventDefault();
switchView(this);
console.log('Testing'); //not firing
});

Event handler unbinded after first click

In Backbone marionette composite view, I am using following code .
events: {
'click th': 'doSort',
'click #selectAllGroups': 'allMembersSelected'
},
allMembersSelected: function(event) {
var selectAll;
if ($("#selectAllGroups").prop('checked') == true) {
selectAll = true;
} else {
selectAll = false;
}
var allCheckboxes = document.getElementsByName("selectGroupCheckBox");
for (var i = 0, n = allCheckboxes.length; i < n; i++) {
allCheckboxes[i].checked = selectAll;
}
},
where #selectAllGroups is actually checkbox to select and unselect all checkboxes in the list.
the function allMembersSelected is called only first time when the checkbox is clicked , it wouldn't be called on any subsequent clicks.
One Interesting point is that If I remove the below section from code, the click handler would be called on subsequent clicks and the issue wouldn't come.
if ($("#selectAllGroups").prop('checked') == true) {
selectAll = true;
} else {
selectAll = false;
}
You can update this function as:
allMembersSelected: function(event) {
event.stopPropagation(); // add this one too, as seems event is bubbling up.
$('input[type="checkbox"][name="selectGroupCheckBox"]')
.prop('checked', $("#selectAllGroups").prop('checked'));
},
It will mark check all the checkboxes named "selectGroupCheckBox" only when #selectAllGroups checkbox is checked.
This code block:
events: {
'click th': 'doSort', // 2. when event comes here all the elements on the row gets replaced by new rows.
'click #selectAllGroups': 'allMembersSelected' // 1. click on it bubbles up to the parent th
},
I find it that when you click on th it sorts all the rows and replaces all the elements with the new ones. So all the child elements inside every th if they have any event bound on it that will bubble up to the dom and that would cause in sort.
Same thing is happening with your #selectAllGroups checkbox as it is in the th or i would say that should be in the th so any event bound on it bubbles up to the th which causes in sorting and it feels that event is not working on checkbox but it does.

Selectize.js: onItemAdd event triggered when silently adding an item

Using Selectize.js, I'm trying to initialize the dynamically pre-select one of the item of the list without triggering the onItemAdd event. In the following code, the event is triggered even if the silent parameter is truthy:
$(function () {
$('select').selectize({
onItemAdd: function () {
alert("Add item");
}
});
// this triggers an the event
$('select')[0].selectize.addItem('2', true);
});
JSFiddle: http://jsfiddle.net/zuzat0dc/1/
According to the documentation:
addItem(value, silent): "Selects" an item. Adds it to the list at the current caret position. If "silent" is truthy, no change event will be fired on the original input.
Any idea how to avoid triggering the onItemAdd event? Is the silent parameter b0rked or should I use the change event instead?
A quick fix that worked for me was to keep a state flag and refer to it in the event handler...
$(function () {
var initialising = true;
$('select').selectize({
onItemAdd: function () {
if(!initialising) {
alert("Add item");
}
}
});
// this triggers an the event
$('select')[0].selectize.addItem('2', true);
initialising = false;
});
The silent parameter in addItem(value, silent) affects only to the fact whether or not the change event. You can't avoid item_add event with silent = true.
The only thing that worked for me was to store item_add event locally, remove it from selectize instance and set it back after I added the item:
onItemAdd: function(val) {
var e = this._events['item_add'];
delete this._events['item_add'];
this.addItem(123);
this._events['item_add'] = e;
}

Avoid clicking twice to begin editing boolean (checkbox) cell in Backgrid

We are using Backgrid and have discovered that to begin editing a "boolean" (checkbox) cell in Backgrid, you must click twice: the first click is ignored and does not toggle the state of the checkbox. Ideally we would get to the root of what is causing this behavior (e.g. is preventDefault being called) and solve it there, but I at first I tried a different approach with the following extension of BooleanCell's enterEditMode method which seemed like a logical place since it was upon entering edit mode that the checkbox click was being ignored.
Problem is my attempt also toggles the state of the previously edited checkbox. Here is the code.
var BooleanCell = Backgrid.BooleanCell.extend({
/*
* see https://github.com/wyuenho/backgrid/issues/557
*/
enterEditMode: function () {
Backgrid.BooleanCell.prototype.enterEditMode.apply(this, arguments);
var checkbox = this.$('input');
checkbox.prop('checked', !checkbox.prop('checked'));
}
});
The following seems to work:
var BooleanCell = Backgrid.BooleanCell.extend({
editor: Backgrid.BooleanCellEditor.extend({
render: function () {
var model = this.model;
var columnName = this.column.get("name");
var val = this.formatter.fromRaw(model.get(columnName), model);
/*
* Toggle checked property since a click is what triggered enterEditMode
*/
this.$el.prop("checked", !val);
model.set(columnName, !val);
return this;
}
})
});
This is because the render method gets called by Backgrid.BooleanCell's enterEditMode method on click, and said method destroys and re-creates the checkbox as follows but in so doing loses the checked state (after the click) of the original "non-edit-mode" checkbox
this.$el.empty();
this.$el.append(this.currentEditor.$el);
this.currentEditor.render();
A simpler approach:
var OneClickBooleanCell = Backgrid.BooleanCell.extend({
events: {
'change input': function(e) {
this.model.set(this.column.get('name'), e.target.checked);
},
},
});
This bypasses the CellEditor mechanism entirely and just reacts to the input event on the checkbox by updating the model.

Select Tag Change Event Call on Selected Index Change

I have a select tag that has an eventListener on change.
Now I also have two different buttons that change it, that uses:
(selectTag).selectedIndex++;
The above does what I want to achieve, but it does not call my function callback on change.
How would I go about doing that? Other Approaches welcomed.
I would prefer pure-JS solutions, (noJquery please).
Just trigger change event when calling click handler on buttons:
var select = document.querySelector("select");
var button = document.querySelector("button")
select.addEventListener("change", function (e) {
alert(e.target.value)
});
button.addEventListener("click", function () {
var event;
try {
event = new Event("change")
} catch (e) {
event = document.createEvent("Event");
event.initEvent("change", true, false);
}
select.selectedIndex++;
select.dispatchEvent(event);
});
JS Bin
Update: I've changed it work in IE 10 and probably some others.

Categories

Resources