Javascript removes click handlers - javascript

I am new to javascript and I have written this javascript class to generate a table nested in an unordered list. I want to save the state on the table as on the main page I have multiple tabs and when I come back to the tab which displays this table it should have the same state as before. In my main script file I am creating an instance of this class and generating the custom table from the data only once during initialisation. I am calling the updateTable() method to add new data to the table every time this tab is opened, which adds new data to the ul and returns this.ul . I am able the save the state of the table but after the first time when I come back to this tab I am unable to trigger click events. Somehow the event handlers are not getting called after the 1st time.
import {TaskQueue} from './run-task-queue.js';
export class Table {
constructor(groups,file_dir, list_type) {
this.ul = $('<ul style="padding-top:10px;"></ul>');
this.data = groups;
this.type = list_type;
this.file_dir = file_dir;
this.selected = {};
this.runTaskQueue = new TaskQueue();
}
addTableHeader() {
var hdr = $('<li></li>');
var hdrDiv = $('<div class="row" style="margin:0;background-color:aliceblue"></div>');
var hdrCheckbox = $('<div class="my-auto" style="padding:10px"><input class="float-left" type="checkbox" style="cursor:pointer"></div>');
var hdrPlayIconDiv = $('<div class="my-auto float-right" style="padding:10px; flex:1; color:green;"></div>');
var hdrPlayIcon = $('<i class=" fa fa-play float-right" data-run-status="notrunning" style="cursor:pointer"></i>');
hdrPlayIcon.on('click',function(e){
status = e['target'].getAttribute("data-run-status");
if(status === 'running') {
e['target'].classList = ''
e['target'].classList = 'fa fa-play float-right';
e['target'].setAttribute("data-run-status", "notrunning");
this.runTaskQueue.clearTaskQueue();
}
else {
e['target'].classList = ''
e['target'].classList = 'fa fa-pause float-right';
e['target'].setAttribute("data-run-status", "running");
this.runTaskQueue.enqueueTaskList(this.selected);
}
}.bind(this));
hdr.css('cursor','default');
hdrDiv.append(hdrCheckbox);
hdrPlayIconDiv.append(hdrPlayIcon);
hdrDiv.append(hdrPlayIconDiv);
hdr.append(hdrDiv)
this.ul.append(hdr);
}
generateTableRow(val) {
var row = $('<tr></tr>');
var cell = $('<td></td>').text(val);
if(this.type === 'test') {
var checkboxCell = $('<td></td>');
var checkbox = $('<input type="checkbox">');
checkbox.on('click', function(e){
if(!e.target.checked)
delete this.selected[val]
else {
var task = {};
task['file_name'] = val;
task['file_dir'] = this.file_dir;
var x = ($(e.target).parent().siblings()[2]);
task['element'] = x.children[0].children[0];
task['doneClassList'] = "fa fa-play float-right";
task['queueClassList'] = "fa fab fa-stack-overflow float-right",
task['runningClassList'] = "fa fa-spinner fa-spin float-right",
this.selected[val] = task;
}
console.log(this.selected)
}.bind(this));
checkboxCell.append(checkbox);
row.append(checkboxCell);
}
row.append(cell);
if(this.type ==='replay' || this.type ==='test') {
var editIcon = $('<td style="flex:1;"><div class="my-auto float-right" style="padding:10px; color:#15AABF;"><i class=" fa fa-edit float-right"></i></div></td>');
row.append(editIcon);
}
if(this.type === 'test') {
var playIcon = $('<td style="flex:1;"><div class="my-auto float-right" style="padding:10px; color:green;"><i class="fa fa-play float-right"></i></div></td>');
playIcon.on('click', function(e){
console.log(e);
console.log(this);
var element = e['target'];
// element.classList.remove("fa-play");
// element.classList.add('fa-spinner');
// element.classList.add('fa-spin');
this.runTaskQueue.enqueueTask({'file_name': val,'file_dir': this.file_dir, 'element':e.target,
'queueClassList' : "fa fab fa-stack-overflow float-right",
'runningClassList': "fa fa-spinner fa-spin float-right",
'doneClassList':"fa fa-play float-right"});
//e['target'].classList.remove('color','blue');
}.bind(this))
row.append(playIcon);
}
return row;
}
generateTableListItem(key) {
var li = $('<li class="hide_group"></li>');
var div = $('<div class="row" style="margin:0;"></div>');
var p = $('<div class="my-auto" style="padding:10px;flex:1"></div>').append($('<p class="my-auto"></p>').text(key));
var i = $('<div class="my-auto float-right" style="padding:10px" ><i class=" fa fa-plus float-right"></i></div>');
p.on('click',function(){
$(this).parent().parent().toggleClass('hide_group');
});
i.on('click',function(){
$(this).parent().parent().toggleClass('hide_group');
})
var nestedTable = $('<table class="tabel table-hover" style="width:98%; margin-left:20px;"></table>');
this.data[key].forEach(val => {
var row = this.generateTableRow(val);
nestedTable.append(row);
})
if(this.type === 'test'){
var checkbox = $(`<div class="my-auto" style="padding:10px"><input class="float-left" type="checkbox" ></div>`);
checkbox.on('click', function(){
console.log('checkbox -clicked')
});
div.append(checkbox);
}
div.append(p);
div.append(i);
li.append(div);
li.append(nestedTable);
return li;
}
generateTableFromGroups() {
this.ul.empty();
if(this.type === 'test')
this.addTableHeader();
Object.keys(this.data).forEach(key => {
var li = this.generateTableListItem(key);
this.ul.append(li);
})
console.log('this.ul');
console.log(this.ul);
return this.ul;
}
updateTable(data) {
var currentData = this.data;
var currentKeys = Object.keys(currentData);
var newData = data;
var newKeys = Object.keys(newData);
var deltaPositive = newKeys.filter(x => !currentKeys.includes(x));
deltaPositive.forEach(key => {
this.data[key] = newData[key];
this.generateTableListItem(key);
});
console.log('this.ul');
console.log(this.ul);
return this.ul;
}
}
Parts of the main script file, the init() function gets the initial data and initialises the tables. $.fn.show_files_list is attached to a button and is responsible for updating the table and displaying it. The table is being displayed when I click this button, but inside the table I have some buttons that should trigger some events. When I come to this tab for the first time all the buttons in the generated table work fine but if I leave this tab and come back to this tab the buttons in the table stop working.
import {Table} from './table-module.js';
$(document).ready(function(){
var testTable;
var replayTable;
const get_file_list = (url) => {
var dfd = jQuery.Deferred();
fetch(url)
.then((resp) => (resp.ok) ?resp.json() : new Error('something went wrong'))
.then(function(data) {
dfd.resolve(data);
})
.catch(err => {
console.log(err);
dfd.reject(err);
})
return dfd.promise();
}
$.fn.show_files_list = function(key1, key2, table) {
$(this).siblings().removeClass('btn-info');
$(this).siblings().addClass('btn-outline-info');
$(this).removeClass('btn-outline-info');
$(this).addClass('btn-info');
get_file_list('/get_file_list')
.done( (all_files) => {
var dir = all_files[key1];
var files = all_files[key2];
var groups = group_files(files);
console.log('Display Table');
var genTable = table.updateTable(groups);
$('#display_files').empty();
$('#display_files').append(genTable);
})
.fail(function(err) {
console.log(err);
});
}
const init = () => {
get_file_list('/get_file_list')
.done( (all_files) => {
var test_dir = all_files['test_dir'];
var test_files = all_files['test_files'];
var test_groups = group_files(test_files);
testTable = new Table(test_groups, test_dir, 'test');
testTable.generateTableFromGroups();
var replay_dir = all_files['repaly_dir'];
var replay_files = all_files['replay_files'];
var replay_groups = group_files(replay_files);
replayTable = new Table(replay_groups, replay_dir, 'replays');
replayTable.generateTableFromGroups();
$.fn.show_logs('aut');
})
.fail((err) => {
console.log(err);
})
}
init();
}
It would be a great help if someone could point me in the right direction.
Edit:
If I use vanilla js to attach event handlers to the elements it works.
With Jquery's on method I am seeing the above mentioned error. See below for the vanilla js event handler that works.
hdrPlayIcon[0].addEventListener('click',function(e){
status = e['target'].getAttribute("data-run-status");
if(status === 'running') {
e['target'].classList = ''
e['target'].classList = 'fa fa-play float-right';
e['target'].setAttribute("data-run-status", "notrunning");
this.runTaskQueue.clearTaskQueue();
}
else {
e['target'].classList = ''
e['target'].classList = 'fa fa-pause float-right';
e['target'].setAttribute("data-run-status", "running");
this.runTaskQueue.enqueueTaskList(this.selected);
}
}.bind(this));
Why is the Jquery's on function not working?

Just use the below method for remove the click listener
document.getElementById("myDIV").removeEventListener("click", myFunction);

Related

Async/await function to show, wait, hide overlay not working in javascript

I'm having a problem with showing an overlay div element and then hiding it again after the runSearch() function has completed. In short, the overlay does not appear at all.
What the overlay should look like if it worked:
If I had to guess, I believe it could relate to a misunderstanding about how to implement async/await correctly in javascript.
Since I am limited for space here, the full Github project is accessible as a fully deployed page here, if you need more context. However, the most relevant excerpts are below:
The overlay div element in index.html:
<div class="overlay d-flex justify-content-center align-items-center">
<h5>Please wait...</h5>
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
The overlay in CSS:
.overlay {
background-color:#EFEFEF;
position: fixed;
width: 100%;
height: 100%;
z-index: 1000;
left: 0px;
display: none!important;
/* without !important, the overlay would immediately kick into effect */
}
The JS functions which show and hide the overlay when called upon:
function loadingOverlayOn() {
document
.getElementsByClassName("overlay")[0]
.style.display = 'block'
}
function loadingOverlayOff() {
document
.getElementsByClassName("overlay")[0]
.style.display = 'none'
}
JS with respect to button #1:
cityInstanceBtn.addEventListener('click',async function(e){
// for use in headings inside runSearch
// reset
globalCityName === null;
globalCityState === null;
globalCityCountry === null;
globalCityName = e.target.dataset.city
globalCityState = e.target.dataset.state
globalCityCountry = e.target.dataset.country
loadingOverlayOn();
await runSearch(cityName, cityState, cityCountry, cityLat, cityLng, units)
loadingOverlayOff();
})
JS with respect to button #2, which occurs inside of a temporarily displayed Bootstrap modal:
cityInstanceBtn.addEventListener('click', async function(){
myModal.hide()
globalCityName = document.getElementById(id).dataset.city
globalCityState = document.getElementById(id).dataset.state
globalCityCountry = document.getElementById(id).dataset.country
loadingOverlayOn();
await runSearch(cityName, cityState, cityCountry, cityLat, cityLng, units)
loadingOverlayOff();
})
The JS function during which the overlay should be shown, and hidden once its execution is complete:
async function runSearch(
cityName,
cityState,
country,
cityLat,
cityLng,
detectedUnits
) {
console.log("check cityState: " + cityState);
console.log("check globalCityState: " + globalCityState);
var h2Today = document.getElementById("today-title");
var h2Next5Days = document.getElementById("next-5-days-title");
if (globalCityState != "undefined" && globalCityName && globalCityCountry) {
h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName}, ${globalCityState}, ${globalCityCountry}</span>`;
h2Next5Days.innerHTML = `<span class="orange">4-day</span> outlook for <span class="cornflowerblue">${globalCityName}, ${globalCityState}, ${globalCityCountry}</span>`;
} else if (
(globalCityState = "undefined" && globalCityName && globalCityCountry)
) {
h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName},${globalCityCountry}</span>`;
h2Next5Days.innerHTML = `<span class="orange">4-day</span> outlook for <span class="cornflowerblue">${globalCityName}, ${globalCityCountry}</span>`;
}
var newSearchObject = {
cityName: cityName,
cityState: cityState,
cityCountry: country,
cityLat: cityLat,
cityLng: cityLng,
detectedUnits: detectedUnits,
};
var retrievedLocalStorage = localStorage.getItem("savedCities");
retrievedLocalStorage = JSON.parse(retrievedLocalStorage);
// const arr = retrievedLocalStorage.map(a => {a.cityLat, a.cityLng})
if (retrievedLocalStorage === null) {
localStorage.setItem("savedCities", JSON.stringify([newSearchObject]));
generatePrevCitiesList();
} else if (
retrievedLocalStorage.length > 0 &&
retrievedLocalStorage.length < 5
) {
retrievedLocalStorage.reverse();
if (
!retrievedLocalStorage.some((s) => {
return (
s.cityLat == newSearchObject.cityLat &&
s.cityLng == newSearchObject.cityLng
);
})
) {
// Check if an array of objects contains another object: https://stackoverflow.com/a/63336477/9095603
// this solution which converts objects to string first isn't entirely reliable if you can't guarantee the same order is preserved, for example: https://stackoverflow.com/a/201305/9095603
retrievedLocalStorage.push(newSearchObject);
retrievedLocalStorage.reverse();
console.log("existingSearchObject2: " + retrievedLocalStorage);
localStorage.setItem(
"savedCities",
JSON.stringify(retrievedLocalStorage)
);
}
generatePrevCitiesList();
} else if (retrievedLocalStorage.length >= 5) {
retrievedLocalStorage.reverse();
if (
!retrievedLocalStorage.some((s) => {
return (
s.cityLat == newSearchObject.cityLat &&
s.cityLng == newSearchObject.cityLng
);
})
) {
retrievedLocalStorage.push(newSearchObject);
}
while (retrievedLocalStorage.length > 5) {
retrievedLocalStorage.shift();
}
retrievedLocalStorage.reverse();
localStorage.setItem("savedCities", JSON.stringify(retrievedLocalStorage));
generatePrevCitiesList();
}
fetch(
`https://api.openweathermap.org/data/2.5/forecast?lat=${cityLat}&lon=${cityLng}&units=${detectedUnits}&appid=${apiKey}`
)
.then((response) => response.json())
.then((data) => {
console.log(data);
console.table(data.list);
console.log(JSON.stringify(data));
var timezone = data.city.timezone;
console.log({ timezone });
var country = data.city.country;
console.log({ country });
var cityName = data.city.name;
console.log({ cityName });
var datesArray = [];
console.log({ datesArray });
const days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
// var h2Today = document.getElementById('today-title')
// h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName}, ${globalCityState}, ${globalCityCountry}</span>`
// }
// h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName},${globalCityCountry}</span>`
// }
for (let i = 0; i < data.list.length; i++) {
var unixTimestamp = data.list[i].dt;
console.log(data.list[i].dt);
// you don't need it for dt_txt but if you want to use the unix timestamp in the data, you can do this conversion:
var jsTimestamp = unixTimestamp * 1000;
var date = new Date(jsTimestamp);
var basicDateLocalAU = date.toLocaleDateString("en-AU");
var basicDateLocalUS = date.toLocaleDateString("en-US");
var basicDateLocalUser = date.toLocaleDateString(`en-${country}`);
console.log(basicDateLocalAU); // Prints: 5/6/2022
console.log(basicDateLocalUS); // Prints: 6/5/2022
console.log(basicDateLocalUser); // Prints: 6/5/2022
var timeLocalAU = date.toLocaleTimeString("en-AU", {
hour: "2-digit",
minute: "2-digit",
}); // Prints: 13:10:34
// https://stackoverflow.com/a/20430558/9095603
// https://bobbyhadz.com/blog/javascript-typeerror-date-getday-is-not-a-function#:~:text=getDay%20is%20not%20a%20function%22%20error%20occurs%20when%20the%20getDay,method%20on%20valid%20date%20objects.
data.list[i].basicDateLocalAU = basicDateLocalAU;
data.list[i].basicDateLocalUS = basicDateLocalUS;
data.list[i].basicDateLocalUser = basicDateLocalUser;
data.list[i].dayOfWeekIndex = date.getDay();
data.list[i].dayOfWeekValue = days[date.getDay()];
data.list[i].basicTime = timeLocalAU;
// https://bobbyhadz.com/blog/javascript-array-push-if-not-exist
if (!datesArray.includes(basicDateLocalUser)) {
datesArray.push(basicDateLocalUser);
var dayOfWeek = days[date.getDay()];
console.log(dayOfWeek);
}
}
console.log({ date });
console.log({ data });
var datalist = data.list;
console.log({ datalist });
var obj = groupBy(datalist, "basicDateLocalAU");
console.log({ obj });
// const result = data.list.group(({ basicCalendarDateAU }) => basicCalendarDateAU);
for (let i = 0; i < obj.length; i++) {
var dayTableEle = document.querySelector(`#day${i} table`);
// var textNode = document.createTextNode(`${dayOfWeekValue}`);
dayTableEle.innerHTML = `<row><th>Time</th><th>Temp</th><th></th><th>Conditions</th><th>Humidity</th><th>Wind speed</th></row>`;
for (let j = 0; j < obj[i].length; j++) {
console.log(obj[i].length);
if (!document.querySelector(`#day${i} h5`).innerText) {
document.querySelector(
`#day${i} h5`
).innerText = `${obj[i][j].dayOfWeekValue}`;
}
if (
!document.querySelector(`#day${i} span#usercountry-dateformat`)
.innerText
) {
document.querySelector(
`#day${i} span#usercountry-dateformat`
).innerText = `${obj[i][j].basicDateLocalUser}`;
}
if (
!document.querySelector(`#day${i} span#AU-dateformat`).innerText
) {
document.querySelector(
`#day${i} span#AU-dateformat`
).innerText = `${obj[i][j].basicDateLocalAU}`;
document
.querySelector(`#day${i} span#AU-dateformat`)
.style.setProperty("display", "none");
}
if (
!document.querySelector(`#day${i} span#US-dateformat`).innerText
) {
document.querySelector(
`#day${i} span#US-dateformat`
).innerText = `${obj[i][j].basicDateLocalUS}`;
document
.querySelector(`#day${i} span#US-dateformat`)
.style.setProperty("display", "none");
}
// var kelvinToCelcius = obj[i][j].main.temp - 273.15;
var tempMetric;
var tempImperial;
var windSpeedImperial;
var windSpeedMetric;
if (units == "metric") {
var tempMetric = obj[i][j].main.temp;
tempMetric = roundedToFixed(tempMetric, 1);
var tempImperial = tempMetric * 1.8 + 32;
tempImperial = roundedToFixed(tempImperial, 1);
var windSpeedMetric = obj[i][j].wind.speed;
windSpeedMetric = roundedToFixed(windSpeedMetric, 1);
var windSpeedImperial = windSpeedMetric * 2.23694;
windSpeedImperial = roundedToFixed(windSpeedImperial, 1);
var metricDisplay = "inline";
var imperialDisplay = "none";
} else if (units == "imperial") {
var tempImperial = obj[i][j].main.temp;
tempImperial = roundedToFixed(tempImperial, 1);
var tempMetric = (tempImperial - 32) / 1.8;
tempMetric = roundedToFixed(tempMetric, 1);
var windSpeedImperial = obj[i][j].wind.speed;
windSpeedImperial = roundedToFixed(windSpeedImperial, 1);
var windSpeedMetric = windSpeedImperial / 2.23694;
windSpeedMetric = roundedToFixed(windSpeedMetric, 1);
var metricDisplay = "none";
var imperialDisplay = "inline";
}
dayTableEle.innerHTML += `
<row>
<td id="tdTime">${obj[i][j].basicTime}</td>
<td id="tdTemp">
<span class="temp-metric metric" style="display:${metricDisplay};">${tempMetric} ${tempUnitsMetric}</span>
<span class="temp-imperial imperial" style="display:${imperialDisplay};">${tempImperial} ${tempUnitsImperial}</span>
</td>
<td><img src="https://openweathermap.org/img/wn/${obj[i][j].weather[0].icon}.png" alt="weather icon"></td>
<td id="tdConditions">${obj[i][j].weather[0].description}</td>
<td id="tdHumidity">${obj[i][j].main.humidity} %</td>
<td id="tdWindSpeed">
<span class="windspeed-metric metric" style="display:${metricDisplay};">${windSpeedMetric} ${windSpeedUnitsMetric}</span>
<span class="windspeed-imperial imperial" style="display:${imperialDisplay};">${windSpeedImperial} ${windSpeedUnitsImperial}</span>
</td>
<td id="tdWindDir"><i style="transform: rotate(${obj[i][j].wind.deg}deg)" class="fa-solid fa-arrow-up"></i></td>
</row>
`;
}
}
});
}
We can see here that the event listener is properly attached - this is true of both buttons but I'll show one here just to be representative:
Full Github project is accessible as a fully deployed page here.
To reiterate, the problem is that the overlay does not appear at all during this sequence of events and I'm seeing page elements prematurely before the page is built:
loadingOverlayOn();
await runSearch(cityName, cityState, cityCountry, cityLat, cityLng, units)
loadingOverlayOff();
You are not awaiting fetch, you are using then instead.
You have to await fetch
See below example
const response = await fetch(url);
const jsonData = await response.json()

Why does the swapping function is not working with new elements?

I am creting a todo list having a default list and then adding new todos to it. It is possible do drag and drop the elements to rearrenge them. That swapping function works perfectly with the default list but does not work with the new ones added. I am not sure why it is not working as it gets undefined
This is the code:
const draggableElement = document.getElementById('draggable-list');
const TodoList = [
'Complete online Javascript course',
'Jog around the park 3x',
'10 minutes meditation',
'Read for 2hr',
'Pick up the groceries',
'Complete todo list',
];
//store items
const listItems = [];
let dragStartIndex;
createList();
//insert items into dom
function createList() {
[...TodoList] //copies array
.forEach((todo, index) => {
const listItem = document.createElement('li');
// listItem.setAttribute('id','draggable');
listItem.setAttribute('data-index', index + 1);
listItem.setAttribute('className', 'draggable');
listItem.innerHTML = `
<label for="showRatings${index + 1}" class="circle${index + 1} check">
<input type="checkbox" class="checkbox input" name="showRatings${index + 1}" id="showRatings${index + 1}">
</label>
<span class="number">${index + 1+"-"}</span>
<div class="draggable" draggable="true">
<p class="todo-name" >${todo}</p>
</div>`;
listItems.push(listItem);
draggableElement.appendChild(listItem);
});
}
addEventListeners();
function dragStart() {
dragStartIndex = +this.closest('li').getAttribute('data-index');
// console.log('index',dragStartIndex)
}
function dragEnter() {
this.classList.add('over');
}
function dragLeave() {
this.classList.remove('over');
}
function dragOver(e) {
e.preventDefault();
// console.log('over')
}
///////////////////////////////////////////////////////
function dragDrop() {
const dragEndIndex = +this.getAttribute('data-index');
swapItems(dragStartIndex - 1, dragEndIndex - 1);
this.classList.remove('over');
}
function swapItems(fromIndex, toIndex) {
const itemOne = listItems[fromIndex].querySelector('.draggable');
const itemTwo = listItems[toIndex].querySelector('.draggable');
// console.log(itemOne,itemTwo);
// console.log(listItems[fromIndex])
listItems[fromIndex].appendChild(itemTwo);
listItems[toIndex].appendChild(itemOne);
}
function addEventListeners() {
const draggables = document.querySelectorAll('.draggable');
const dragListItems = document.querySelectorAll('.draggable-list li');
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', dragStart);
});
dragListItems.forEach(item => {
item.addEventListener('dragover', dragOver);
item.addEventListener('drop', dragDrop);
item.addEventListener('dragenter', dragEnter);
item.addEventListener('dragleave', dragLeave);
});
}
const todoInput = document.querySelector('#todo-input');
const todos = [];
var index2 = 6;
todoInput.addEventListener('keyup', function(e) {
if (e.key == 'Enter' || e.keyCode == 13) {
// index2++;
// todos.push(e.target.value);
newTodo(e.target.value);
todoInput.value = '';
}
})
function newTodo(value) {
const todo = document.createElement('div');
const todoText = document.createElement('p');
todoText.classList.add('todo-name')
const todoCheckbox = document.createElement('input');
const todoCheckBoxLabel = document.createElement('label');
todo.setAttribute('draggable', true);
todo.classList.add('draggable')
const numberSpan = document.createElement('span');
numberSpan.classList.add('number')
const todoLi = document.createElement('li');
todoLi.setAttribute('className', 'draggable');
todoLi.classList.add('list-item', 'not-crossed')
const toDosContainer = document.querySelector('.draggable-list')
const Container = document.querySelector('.container-todo')
todoCross = document.createElement('span');
todoCross.classList.add('cross')
todoLi.setAttribute('data-index', index2);
// let content =[index2+ "-" + ' ' + value ];
// var arrayValue = content.toString().replace(/,/g, "")
numberSpan.textContent = "-";
todoText.textContent = value;
todoCheckbox.type = "checkbox";
todoCheckbox.name = "checkbox";
todoCheckBoxLabel.htmlFor = "checkbox";
todoCheckBoxLabel.addEventListener('click', function(e) {
if (todoCheckbox.checked) {
todoCheckbox.checked = false;
todoText.style.textDecoration = 'none';
todoCheckBoxLabel.classList.remove('active');
todoLi.classList.add('not-crossed')
todoLi.classList.remove('thick-crossed')
} else {
todoCheckbox.checked = true;
todoText.style.textDecoration = "line-through";
todoCheckBoxLabel.classList.add('active');
todoLi.classList.remove('not-crossed')
todoLi.classList.add('thick-crossed')
}
});
TodoList.push(todoText.textContent);
listItems.push(todoText.textContent);
console.log('lista', listItems);
todoCross.textContent = 'X';
todoCross.addEventListener('click', function(e) {
e.target.parentElement.remove();
});
Container.classList.add('todos-container');
todo.classList.add('todo');
todoCheckbox.classList.add('checkbox')
todoCheckBoxLabel.classList.add('circle', 'chk');
// todoCross.classList.add('cross');
todo.appendChild(todoCheckbox);
todo.appendChild(todoCheckBoxLabel);
todo.appendChild(numberSpan)
todo.appendChild(todoText);
todo.appendChild(todoCross);
todoLi.appendChild(todo);
toDosContainer.appendChild(todoLi)
}
<body>
<main>
<div class="header">
<h1 class="title">TODO</h1>
<div onclick="changeTheme()" class="tgl-btn"></div>
</div>
<div class="type-todo">
<div class="circle"></div>
<input type="text" value="" id="todo-input">
</div>
<div class="container-todo">
<ul class="draggable-list" id="draggable-list">
</ul>
<div class="footer-div" id="footer-div"></div>
</div>
<p class="note">Drag and drop to reorder list</p>
</main>
<script src="./index.js"></script>
</body>
Thank you in advance and I hope you can help me

Is there way to get the corresponding item using next and next all expression of jquery

I have module regarding getting the right corresponding parent item and parent child, so to get the each item and the child I use the next and nextAll expression of jquery. I will share to you guys my output right now, and the output I want to be.
This is my output right now (Which this output is wrong)
The output should be look like this
My output in my web app. as you can see on my highlighted items there is no children however in my console log when I submit the button the highlighted item repeat the output on the first item ordered
To append the item to that list I use this code.
$("tr#productClicked").click(function () {
var menu_name = $(this).closest("tr").find(".menu_name").text();
var menu_price = $(this).closest("tr").find(".menu_price").text();
var chain_id = $(this).closest("tr").find(".chain_id").text();
var menu_image = $(this).closest("tr").find(".menu_image").attr('src');
swal({
title: "Are you sure to add " + menu_name + " ?",
text: "Once you will add it will automatically send to the cart",
icon: "warning",
buttons: true,
dangerMode: true,
})
.then((willInsert) => {
if (willInsert) {
swal("Successfully Added to your form.", {
icon: "success",
});
if(chain_id == 0) {
$("tbody#tbody_noun_chaining_order").
append("<tr class='condimentParent' style='background-color:'black !important',color:'white !important' '><td></td><td>"+menu_name+"</td><td class='total'>"+menu_price+"</td><td><button class='removeorderWithOutCondi btn btn-danger form-control'><i class='far fa-trash-alt'></i></button></td></tr>");
}
else
{
$.ajax({
url:'/get_noun_group_combination',
type:'get',
data:{chain_id:chain_id},
success:function(response){
var noun_chaining = response[0].noun_chaining;
$("tbody#tbody_noun_chaining_order").
append("<tr class='condimentParent' style='background-color:'black !important',color:'white !important' '><td></td><td>"+menu_name+"</td><td class='total'>"+menu_price+"</td><td><button class='removeorderWithCondi btn btn-danger form-control'><i class='far fa-trash-alt'></i></button></td></tr>");
$.each(noun_chaining, function (index, el) {
var stringify_noun_chaining = jQuery.parseJSON(JSON.stringify(el));
// console.log(stringify['menu_cat_image']);
var Qty = stringify_noun_chaining['Qty'];
var Condiments = stringify_noun_chaining['Condiments'];
var Price = stringify_noun_chaining['Price'];
var allow_to_open_condiments = stringify_noun_chaining['allow_to_open_condiments'];
var condiments_section_id = stringify_noun_chaining['condiments_section_id'];
$("tbody#tbody_noun_chaining_order").
append("<tr class='editCondiments'>\
<td class='condiments_order_quantity'>"+Qty+"</td>\
<td>*"+Condiments+"</td><td class='total'>"+Price+"</td>\
<td class='allow_to_open_condiments_conditional' style='display:none;'>"+allow_to_open_condiments+"</td>\
<td class='condi_section_id' style='display:none;'>"+condiments_section_id+"</td>\
</tr>");
})
},
error:function(response){
console.log(response);
}
});
}
}
});
This is my add to cart button when inserting the item to the database.
$('button#add_to_cart').on('click',function () {
var customer_id = $('#hidden_customer_id').val();
$parent = $(this).closest("tr.condimentParent");
var menu= $('#noun_chaining_order').find('tr.condimentParent');
menu.next('.condimentParent').add(menu).each(function(){
if(menu.length > 0 ) {
var $tds_menu = $(this).find("td");
Qty_menu = $tds_menu.eq(0).text(),
Item_menu = $tds_menu.eq(1).text(),
Price_menu = $tds_menu.eq(2).text();
console.log(Item_menu);
var condiments= $('#noun_chaining_order').find('tr.editCondiments');
condiments.nextAll('.editCondiments').add(condiments).each(function(){
var $tds_condiments = $(this).find("td");
Qty_condiments = $tds_condiments.eq(0).text(),
Item_condiments = $tds_condiments.eq(1).text(),
Price_condiments = $tds_condiments.eq(2).text();
console.log(Item_condiments);
});
}
});
});
To solved my problem i use multiple add
$('button#add_to_cart').on('click',function () {
var customer_id = $('#hidden_customer_id').val();
$parent = $(this).closest("tr.condimentParent");
var condiments= $('#noun_chaining_order').find('tr.editCondiments');
var menu= $('#noun_chaining_order').find('tr.condimentParent');
menu.next('.condimentParent').add(menu).add(condiments).each(function(){
var $tds_menu = $(this).find("td");
Qty_menu = $tds_menu.eq(0).text(),
Item_menu = $tds_menu.eq(1).text(),
Price_menu = $tds_menu.eq(2).text();
console.log(Item_menu);
// condiments.nextAll('.editCondiments').add(condiments).each(function(){
// var $tds_condiments = $(this).find("td");
// Qty_condiments = $tds_condiments.eq(0).text(),
// Item_condiments = $tds_condiments.eq(1).text(),
// Price_condiments = $tds_condiments.eq(2).text();
// console.log(Item_condiments);
// });
});
});

How to persist selection checkbox state when paging or changing tab on the kendo grid

I want to persist selection of checkbox while paging or moving on other tab in kendo grid .I have referred "How to keep current checkbox state when paging on the grid" here and but i didn't get value of checked and checkbox and also confused with the steps.Please guide in detail.I have attached code below.I have attached script code kendo ui code and html code below.Also thought to use Session to store values of selected checkbox but i don't know is it right way or not.
Please guide me as soon as possible.
<div class="dashboardCharts" id="grid-display">
<div class="count-detail-top right">
<div class="count-detail-bg right">
<ul id="ulOptions">
<li id="Employee" data-type="employee">Employee</li>
<li id="Visitor" data-type="visitor">Visitor</li>
</ul>
</div>
</div>
#(Html.Kendo().Grid<xyz.Models.abcModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.Employee_id).Title("Alert On").Width(200)
.ClientTemplate("<input type=\"checkbox\" class=\"checkbox\" data-id=\"#= Employee_id#\"/>").Sortable(false);
columns.Bound(c => c.Employee_name).Title("Employee Name");
})
.NoRecords("No Records Found")
.Events(e => e.DataBound("onDataBound"))
.DataSource(dataSource => dataSource
.Transport(transport =>
transport
.Read(read => read.Url(DataUrl))
.ParameterMap("parameterMap")
))
)
</div>
//code in script :
<script>
function onDataBound(e) {
$(".checkbox").bind("click", function (e) {
e.stopPropagation();
$(e.target).closest("tr").toggleClass("k-state-selected");
var tr = $(e.target).closest("tr");
var chk = $(tr).find(".checkbox");
var selected = $(chk).attr("data-id");
var a = selectedIDs.includes(selected);
if (a != true) {
if ($(chk).prop("checked")) {
selectedIDs.push(selected);
}
else {
selectedIDs.pop(selected);
}
}
});
var gridDataView = $("#grid").data().kendoGrid.dataSource.view();
for (var i = 0; i < gridDataView.length; i++) {
var panelApplicationId = gridDataView[i].Checkbox;
if (ShouldBeChecked(panelApplicationId)) {
$('#grid tr td input').eq(i).prop("checked", true);
}
}
}
$(document).on('click', 'input.checkbox', function (e) {
var checked = $(this).prop("checked");
var gridDataView = $("#grid").data().kendoGrid.dataSource.view();
console.log(gridDataView);
var idx = $(this).closest("tr").find("td:nth-child(1)").text();
var gridData = $("#grid").data().kendoGrid.dataSource.data();
for (var i = 0; i < gridData.length; i++) {
if (gridData[i].ID == idx) {
gridData[i].Checkbox = checked;
break;
}
}
});
function ShouldBeChecked(panelApplicationId) {
var shouldBeChecked = false;
var gridData = $("#grid").data().kendoGrid.dataSource.data();
for (var i = 0; i < gridData.length; i++) {
if (gridData[i].Checkbox == panelApplicationId) {
if (gridData[i].Checkbox) {
shouldBeChecked = true;
}
break;
}
}
return shouldBeChecked;
}
</script>
code for selected checkbox and and not selected checkbox.
<input type="checkbox" class="checkbox" data-id="34" checked="checked">
<input type="checkbox" class="checkbox" data-id="30">
As mentioned by OP in question-comment as of the 2017 R2 release, there is a grid-option persistselection
Kendo-versions before that, can add their own code, storing the selection in the change-event, and restoring it in the databoundevent as shown by Kendo in persist-row-selection:
change: function (e, args) {
var grid = e.sender;
var items = grid.items();
items.each(function (idx, row) {
var idValue = grid.dataItem(row).get(idField);
if (row.className.indexOf("k-state-selected") >= 0) {
selectedOrders[idValue] = true;
} else if (selectedOrders[idValue]) {
delete selectedOrders[idValue];
}
});
},
dataBound: function (e) {
var grid = e.sender;
var items = grid.items();
var itemsToSelect = [];
items.each(function (idx, row) {
var dataItem = grid.dataItem(row);
if (selectedOrders[dataItem[idField]]) {
itemsToSelect.push(row);
}
});
e.sender.select(itemsToSelect);
}
(See also this SO-question.)

Assigning Click Event After Altering innerHTML

Using AngularJS w/ Meteor
Essentially, I have a ng-click event on a which calls a function that clones the and places it elsewhere. I changed some of the innerHTML so that there is a 'x' icon for removing the item. I would like to be able to click that new to remove it.
So, I know that setting an attribute of ng-click does not work. I am stuck on how I can make this happen.
my template addClass.html
<tr id="{{$index}}" ng-repeat="class in $ctrl.classes" ng-click="$ctrl.addThisClass($event)">
<td><span class="badge pull-left">{{class.units}}</span> {{class.name}}</td>
<td>{{class.number}}</td>
<td>{{class.teacher}}<span class="glyphicon glyphicon-plus text-danger pull-right"></span></td>
</tr>
the function it calls
addThisClass = function($event) {
var clone, table, tableBody, tableRow, tableRowLength, cmpTableData, tableData, tableDataText, remove, alert, footer;
clone = $event.currentTarget.cloneNode(true);
table = document.getElementById('queuedClasses');
tableBody = table.getElementsByTagName('tbody')[0];
tableRow = tableBody.getElementsByTagName('tr');
tableRowLength = tableBody.getElementsByTagName('tr').length;
tableData = clone.getElementsByTagName('td');
footer = document.getElementById("modalFooter");
tableDataText = tableData[2].textContent;
if (tableRowLength < 7) {
for (var i = 0; i < tableRowLength; i++) {
if (tableRow[i].getElementsByTagName('td')[1].textContent == tableData[1].textContent) {
if (footer.getElementsByClassName('alert').length === 0) {
alert = document.createElement('div');
alert.className = 'alert alert-danger text-left';
alert.id = 'alertMessage';
alert.setAttribute('role', 'alert');
alert.appendChild(document.createTextNode('Sorry, you already added that class to the queue.'));
footer.insertBefore(alert, footer.childNodes[0]);
setTimeout(function() {
$("#alertMessage").fadeTo(500, 0).slideUp(500, function() {
$(this).remove();
});
}, 3000);
}
return;
}
}
remove = '<span class="glyphicon glyphicon-remove text-danger pull-right" style="padding-top: 2px; !important;" title="Delete Class"></span>';
tableData[2].innerHTML = tableDataText + remove;
tableBody.appendChild(clone);
} else {
if (footer.getElementsByClassName('alert').length === 0) {
alert = document.createElement('div');
alert.className = 'alert alert-danger text-left';
alert.id = 'alertMessage';
alert.setAttribute('role', 'alert');
alert.appendChild(document.createTextNode('You cannot have more than 7 classes queued.'));
footer.insertBefore(alert, footer.childNodes[0]);
setTimeout(function() {
$("#alertMessage").fadeTo(500, 0).slideUp(500, function() {
$(this).remove();
});
}, 3000);
}
}
/* Reset Filter */
var input, filterTable, filterTR;
input = document.getElementById("searchForClasses");
input.value = '';
filterTable = document.getElementById("tableClasses");
filterTR = filterTable.getElementsByTagName("tr");
for (i = 0; i < filterTR.length; i++) {
filterTR[i].style.display = "";
}
}

Categories

Resources