which is the last event in Kendo grid after databound - javascript

I am working on a kendo Grid, on its databound event, I have called a function to check whether value in each of the row's second block is greater than first block. If true then I change color of texts inside by adding a class.
But, the problem is the added class gets away finally when I see on browser.
If there are two rows with error the first row that I am editing doesn't hold the class but the later ones holds that well.
dataBound: configureGridProperties,
Code for dataBound is
function configureGridProperties(e) {
try {
if (true) {
$('#grid .k-grid-content tr[role=row]').each(function (i) {
var sh = $(this).find('.sh').text();
var sm = $(this).find('.sm').text()
var eh = $(this).find('.eh').text()
var em = $(this).find('.em').text()
var startMin = parseInt(sh) * 60 + parseInt(sm);
var endMin = parseInt(eh) * 60 + parseInt(em);
if (startMin > endMin) {
showOutputExplicitly('Start time cannot be less than end time');
$(this).find('.sh, .sm,.eh,.em').addClass('timeError');
$('div.k-grid-pager').hide();
errorInTime = false;
}
else {
$(this).find('.sh, .sm,.eh,.em').removeClass('timeError');
if (!$('.timeError').length > 0) {
$('div.k-grid-pager').show();
hideErrorMsgSlow();
errorInTime = true;
}
}
});
}
return false;
} catch (e) {
}
pic for the situation . >
The second row that I just edited(start time 23) doesn't hold the colorChange class, but earlier ones hold that. Is there any other event that occurs after dataBound event?

It happens that when dataBound is called, the grid html elements are not rendered yet with the new data. I know that is strange, but I don't know other way than using setTimeout to make this work. So this may work:
dataBound: function(e) {
window.setTimeout(configureGridProperties.bind(this, e), 1);
}
Reference:
dataBound
bind()

Related

Enable and disable onclick funtion

I am dynamically creating a table where i am adding onclick function to each column.
for (var x = 0; x < r.length; x++) {
//Setting the columns
if (i === 1) {
var headerCell = document.createElement("TH");
headerCell.innerHTML = r[x];
headerCell.id = x;
headerCell.onclick = function () {
sortTable(this.id, name);
}
row.appendChild(headerCell);
}
}
In a specific situation I want to disable the onclick function. Here is the code and it works.
$('#errorTable TH').prop("onclick", null).off("click");
and in another situation i want to reattach the onclick function. And that doesn't work. I want to enable the original function....
Any ideas ?
The way you created your table and adding/removing events are not easily maintainable. I also have some suggestions:
Review your code and define code click handler separately.
If you use jQuery in your project use it every where, if not, do not use it anywhere.
In your code i is undefined.
Add Remove Event Listener with jQuery
First define your handler function:
var myClickHandler = function(){
// this is your click handler
alert('Yes!!!');
}
Select your element and assign to a variable. <div id="clickable">Click Me!</div> must be in the DOM at the time of below script executed.
var element = $('#clickable');
// assign event listener
element.on('click',myClickHandler);
// remove event listener:
element.off('click',myClickHandler);
note that you must have to inform jQuery which handler should be removed.
See a sample https://codepen.io/softberry/pen/BEpove
An alternative is to build a click handler that checks a "kill switch".
var tableClickable = true;
headerCell.onclick = function () {
if (tableClickable) {
sortTable(this.id, name);
}
}
//In a specific situation I want to disable the onclick function.
something.addEventListener('someEvent', function () {
tableClickable = false;
});
//and in another situation i want to reattach the onclick function.
something.addEventListener('someOtherEvent', function () {
tableClickable = true;
});

AngularJS: Write inside input box via JS, Do not transfer the value in the JSON

Background: I have an external device (barcode reader) that sends information back to a tablet when the user scans something. I subscribe to that channel and I need the value to be inside the currently focused cell and write it there.
Bug: I can catch the subscription and write the value visually in the Input box, but it never reaches the JSON underneath.
I also tried $scope.$apply() but it did not change anything (maybe I used it wrong).
"Working" Plunker with the problem
$scope.randomClickOnStuff = function() {
// Here Randomely publish stuff with value so we can write it in specific field.
window.setTimeout(function() {
if (!$scope.stopMe) {
vm.objectOtSubscribeTo.publish(channelToUse, Date.now());
$scope.randomClickOnStuff();
} else {
// Stop the loop.
}
}, 1000);
};
var callbackCompleted = function(resultValue) {
// Important code Here
// Code to write in the input box here.
console.log(resultValue);
if (document.activeElement.localName == "input") {
// Option 1:
//--> Work Visually <-- but do not put the value inside the JSON.
document.activeElement.value = resultValue;
$scope.$apply();
// Option 2:
// http://stackoverflow.com/questions/11873627/angularjs-ng-model-binding-not-updating-when-changed-with-jquery
// Problem: The "document.activeElement.attributes['ng-model'].value" is not link with the scope, but with the ng-repeat row. So I have access to the Scope, but not the Row item.
//var binding = document.activeElement.attributes['ng-model'].value;
// Rule: I might not know where the Item is so I cannot do $scope.complexObject[row][binding]
} else {
console.log("not inside a Input box.");
}
};
vm.objectOtSubscribeTo.subscribe(channelToUse, callbackCompleted);
Thanks
One solution would be to keep track of the selected row and cell by setting them on focus of one of the cells
$scope.focusedRow = false;
$scope.focusedCell = false;
$scope.setFocused = (row, cell) => {
$scope.focusedRow = row;
$scope.focusedCell = cell;
};
/* In callback... */
if ($scope.focusedRow !== false && $scope.focusedCell !== false) {
$scope.$apply(
() => $scope.complexObject[$scope.focusedRow]
["cellInTheRow"][$scope.focusedCell] = resultValue
);
}
<input type="text" ng-model="row.cellInTheRow[key]"
ng-focus="setFocused(rowKey, key)" ng-blur="setFocused(false, false)">
Example: https://plnkr.co/edit/och5PoepJuRde0oONIjm?p=preview

How to update input value reflecting the current value?

I'm building a slider with a tooltip showing the updated value when the thumb is moved either by dragging or by clicking plus/minus button.
It works fine, but when I click plus/minus button AFTER dragging thumb it jumps to another position instead of continuing from where it is. How can I fix it to reflect the last value? Here's fiddle: https://jsfiddle.net/2q1rg56z/12/.
var update_num = $('output').text() * 1;
$('.plus').on('click', function() {
if (update_num < 100) {
$('output').text(++update_num);
$('input').val(update_num).trigger('input');
} else {
$('output').text(100);
}
});
$('.minus').on('click', function() {
if (update_num > 0) {
$('output').text(--update_num);
$('input').val(update_num).trigger('input');
} else {
$('output').text(0);
}
});
(It seems that the latest value should be stored in a var, so what should be the best way to do it?)
The problem is that this line only runs once:
var update_num = $('output').text() * 1;
You should turn it into a function
var update_num = function() { return +$('output').text(); };
Now call it in your code:
if (update_num() < 100) {
/***/
}
See this updated fiddle
Side Note: Note my use of + to convert a string to an integer.See http://www.jstips.co/en/converting-to-number-fast-way/
You have almost given the answer yourself. Whenever the slider is used, you have to update the variable update_num.
In your fiddle there is already the handler to do this:
$('.range-control > input').on('input', function() {
var value = this.value;
//...
So you only have to pull up your update_num so you can access it from the scope of the slider input handler and set it the value.
I updated the fiddle to make it work:
https://jsfiddle.net/2q1rg56z/14/

Global variable scope with event handler for dynamically created element

I want to change the behaviour of a Bootstrap dropdown based on a global state variable. If the uiState variable is 'normal' when it is clicked, it should display the dropdown, but if it's in another state it should do something else. I have the following code:
$(document).ready(function () {
var uiState = 'normal';
// Load HTML for word control from server
var wordUiElement;
$.get('/static/word_ui_element.html', function (data) {
wordUiElement = data;
});
var nwords = 0;
var testClickCounter = 0;
// Make it so dropdowns are exclusively controlled via JavaScript
$(document).off('.dropdown.data-api')
$('#ui-add-word').click(function (event) {
var control = wordUiElement.replace(/wx/g, 'w' + nwords.toString());
$('#ui-spec').append(control);
nwords++;
});
$('#ui-change-state').click(function (event) {
if (uiState === 'word_select') {
uiState = 'normal';
} else {
uiState = 'word_select';
}
console.log(uiState);
});
$('#ui-spec').on('click', '.dropdown .dropdown-toggle', function (event) {
if (uiState === 'normal') {
$(this).dropdown('toggle');
}
else {
testClickCounter ++;
console.log(testClickCounter);
}
});
});
However, when the dropdowns are dynamically created, their behaviour seems to be fixed based on what the uiState variable was when the dropdown was created.
This means that if a dropdown was created when the uiState variable was set to 'normal', no matter what uiState is when it's clicked, it will always show or hide the dropdown. On the other hand if the dropdown was created when uiState was 'word_select', it will always increment and log testClickCounter. It's as if the if statement in the handler is evaluated once when the dropdown is created and preserves whatever the value of uiState was when it was created.
I assume this is a scoping issue, and the event handler is executed when it's created. I want it to check at the time of the click what the value of uiState is, but I don't know how to fix it.
Instantiate the element with data-toggle="dropdown" and remove this property when it changes state, eg:
$('#wx').attr('data-toggle',''); // Dropdown no longer shows
or
$('#wx').attr('data-toggle','dropdown'); // Dropdown shows again
The rest of the trigger continue as usual:
$('#wx').on('click', '.dropdown .dropdown-toggle', function (event) {
if (uiState !== 'normal') {
testClickCounter ++;
console.log(testClickCounter);
}
});

Javascript function changes behavior when passing element ID vs. hard coding it

I have the following Javascript that on a single mouse click in a table cell with id="freq-table" populates consecutive <input> form fields with id="searchTerm(x)" with the cell's value. It's referenced in the <body> tag as:
<body onload="populateFields()>
and <table> tag as:
<table onclick="populateFields()>
var index=0;
function populateFields(){
var ft_id = document.getElementById("freq-table");
var alltds = ft_id.getElementsByTagName("td");
for (var i in alltds) {
alltds[i].onclick = function () {
if(index==0) {
searchTerm1.value = this.innerHTML;
} else {
setThis(this.innerHTML);
}
}
}
if (index<2) {
index++;
} else {
index = 1;
}
}
function setThis(value) {
document.getElementById("searchTerm"+index).value = value;
}
When trying to make the function more universal by passing the element id (as follows), it now takes a SECOND mouse click to start populating the fields.
<table onclick="populateFields(this)" id="freq-table">
function populateFields(element){
var alltds = element.getElementsByTagName("td");
What is it about the revision that's changing the behavior? Am I just incorrectly passing the id? Or is revised function now expecting a variable to be passed to it in <body> tag? It's confusing because: If I am incorrectly passing the id, why would the function work consecutively AFTER the first mouse click? What is the fix for this, please?
You have some heavy code here, where the first table click (or body onload) sets additional click event handlers.
What you should do instead is use event delegation. With event delegation, the click event handler is attached to the table but knows which cell was clicked (the target).
[Update] Code sample based on the above article:
var index=0;
var tableIds=["freq-table1","freq-table2","freq-table3"];
for (var i=0;i<tableIds.length;i++) {
var currentId=tableIds[i];
var table=document.getElementById(currentId);
table.onclick = function(event) {
event = event || window.event;
var target = event.target || event.srcElement;
while(target != this) {
if (target.nodeName == 'TD') {
// target is our cell
setThis(target.innerHTML);
}
target = target.parentNode;
}
// increment index modulo 3
index=(index+1)%3;
}; // end of onclick function
} // end of for loop
Live demo: http://jsfiddle.net/srVmF/2/
I think the call can come from the TD or the TR element. So, the first time the id will be 'undefined'.
Why not call the function with the event and verify the tag name:
<table onclick="populateFields(event)" id="freq-table">
Javascript
function populateFields(e) {
var source = e.target || e.srcElement;
if (e.tagName == 'table') {
var ft_id = document.getElementById(source.id);
Instead of being populated on page load, now you have to click on the table before it populates the fields.
You could leave the page load handler:
<body onload="populateAllFields()">
For every table you add a class:
<table class="mytable">
Then, the code:
function populateAllFields()
{
[].forEach.call(document.getElementsByClassName('mytable'), populateFields);
}
Your <body onload="populateFields()> isn't passing the element you want, so the initial set that would be done when the page loads is no longer happening.
You can fix it by passing the ID instead, and give the onload handler the ID.
function populateFields(id){
var ft_id = document.getElementById(id);
var alltds = ft_id.getElementsByTagName("td");
// and so on...
}
<body onload="populateFields('freq-table')">
<table onclick="populateFields(this.id)">

Categories