Error updating inner HTML element using vanilla Javascript - javascript

I have the following HTML element:
<ul id="list">
<!-- <li class="item">
<i class="fa fa-circle-thin co" job="complete" id="0"></i>
<i class="fa fa-circle-check co" job="complete" id="0"></i>
<p class="text">Drink Coffee</p>
<i class="fa fa-trash-o de" job="delete" id="0"></i>
</li> -->
</ul>
I am populating the li items using javascript as below:
const listItem = document.createElement('li');
listItem.className = 'item';
listItem.innerHTML = `
<i class="fa fa-circle-thin co" job="complete" id="0"></i>
<!-- <i class="fa fa-circle-check co" job="complete" id="0"></i> -->
<p class="text">${todoItem.title}</p>
<i class="fa fa-trash-o de" job="delete" id="0"></i>
`;
listElement.appendChild(listItem);
todoItem is an instance of a TodoItem object:
class TodoItem{
constructor(title, status){
this.title = title;
this.status = status;
//this.isDone = false;
}
}
This is working fine and I am getting the list populated. I have also managed to update the list items when clicked by striking it through like below:
target.parentElement.getElementsByClassName('text')[0].innerHTML = `<s>${todoItem.title}</s>`;
Now I am having problem updating the items to remove the strikethrough. I am trying below code.
const strikeElement = target.parentElement.getElementsByTagName('s')[0];
console.log(textElement)
console.log(strikeElement);
todoItem = new TodoItem(target.parentElement.getElementsByClassName('text')[0].innerHTML, itemStatus.pending);
textElement.replaceChildren();
console.log(target.parentElement.getElementsByClassName('text')[0])
target.parentElement.getElementsByClassName('text')[0].innerHTML = `${todoItem.title}`;
Here is what I get from console for the above code. Notice the insertion of tags everytime I click the list item.

Related

Problem with creating an edit box in Vue.js

Well, I have a problem when creating fields for data editing. The problem is that when editing, all fields with the product name are activated instead of one specific. I know the problem is because I only have one variable responsible for enabling the edit box, but creating more variables will not solve the problem because then there may be thousands of such records.
HTML:
<ul>
<li v-for="product in products" class="single-product" v-bind:key="product.id_product">
<i style="color:#df4a49;padding:5px;" class="fa-solid fa-xmark fa-xl" #click="deleteProduct(product.id_product)"></i>
<p class="product-name"><i #click="enableEditing(product.name)" class="fas fa-edit" style="color:#0575ff;padding-right:5px;"></i>
<span v-if="!editing">{{product.name}}</span> <span v-if="editing"> <input v-model="tempValue" class="input"/>
<button #click="disableEditing"> Edit</button>
<button #click="saveEdit"> Save</button>
</span>
</p>
<span class="product-localization"><span><i class="fas fa-edit" style="color:#0575ff;padding-right:5px;"></i>Lokalizacja: </span>{{produkt.lokalizacja}}</span> <span class="product-key"><span><i class="fas fa-edit" style="color:#0575ff;padding-right:5px;"></i>Klucz: </span>{{product.key}}</span>
<hr />
</li>
</ul>
Data:
editing:false,
tempValue: null,
methods:
enableEditing: function(tempProductName){
this.tempValue = tempProductName;
this.editing=true;
},
disableEditing: function(){
this.tempValue = null;
this.editing = false;
},
saveEdit: function(){
this.value = this.tempValue;
this.disableEditing();
}

When transferred to product-details page,product-id lost from localstorage

I'm trying to develop multi pages e-commerce website...and when click cart div I want to store 'productId' in localstorage and redirect to product detail page but when transfering to product-details page,productId lost from localstorage...so I can't access productId in details page...I want locaclstorage keep "productId" when redirect to product details page
let produtDb = document.querySelectorAll(".row3");
let producttss = JSON.parse(localStorage.getItem("Products"));
producttss.forEach(function (product) {
produtDb.forEach(function (re) {
re.innerHTML += `
<div class="pro hi " data-filter =${product.category} item-filter =${product.filter}>
<div class="info">
<div class="cart" onclick="shoppingCart(${product.id})">
<i class="fas fa-shopping-cart"></i> Add to Cart</div>
<div class="show" onclick="saveData(${product.id})" >Show Details</div>
</div>
<div class="prod"> </div>
<img src="${product.imgSrc}">
<p class="name">${product.name}</p>
<span class="price">${product.price} $</span><span class="stars"><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i></span>
</div>
`
});
});
function saveData(id) {
localStorage.setItem("productId", id);
window.location.href = 'Product-descriptions.html'
}
In the product - details page:
localStorage.getItem("productId");

How to target all elements with Jquery on click

Only first element getting clicked not all, how to get alert on all elements.
Jsfiddle
var btn = document.querySelector(".box i");
btn.onclick = function () {
alert('hello');
}
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
</div>
Try querySelectorAll for select all then attract onclick to all element
var btnlist = document.querySelectorAll(".box i");
btnlist.forEach(element =>{element.onclick = function () {
alert('hello');
}});
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
</div>
Despite the title of the question, you don't currently use jQuery in your code. So, I provide 2 solutions:
jQuery:
jQuery('.box i').click(function() {
alert('hello');
});
Pure JS
window.addEventListener('click', function(e) {
// or e.target.classList.contains('fa-address-book-o')
if (e.target.className === 'fa fa-address-book-o') { // Better to add some additional class to identify element, like "fireAlert" for instance.
alert('hello');
}
});
Alternatively, you could select icons with query selector and add individual event listeners to all of them in a loop, but it's bad for performance & generally not considered a good thing to do.
The reason why it only work on the first element is that using .querySelector() method will select only the first element the meet your selector criteria, to be able to select all the elements you have to use .querySelectorAll() which will return a NodeList which can iterate through like this:
var btns = document.querySelectorAll(".box i");
btns.forEach((el, i) => {
el.onclick = function () {
console.log(`Hello! ${i}`);
}
});
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true">1</i>
<i class="fa fa-address-book-o" aria-hidden="true">2</i>
<i class="fa fa-address-book-o" aria-hidden="true">4</i>
<i class="fa fa-address-book-o" aria-hidden="true">5</i>
</div>

Text of List item <li> does not reflected correctly after edited click save button from modal pop up in Javascript

I have nested list item of <li> structured as below. What I am trying to do is to edit each item text from pop up modal and reflect change after I clicked on button Save.
However, the first list item I edited is working well, but from the second time onward, it does not work as expected.
$(document).ready(function() {
$('.modal').modal(); // modal
var child;
$('body').on('click', '.fa-pencil', function(e) {
var text = $(this).closest("li").clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
child = $(this).closest("li").children();
var li_element = $(this).closest('li');
console.log(li_element);
var dataActive = $(this).closest('li').attr('data-act');
var li_icon = li_element.attr('data-icon');
var modal1 = $('#modal1');
var modalBody = modal1.find('.modal-content');
modalBody.find('h4.itemdes').text('');
modalBody.find('.modalBody').html('');
var modalHeader = modalBody.find('h4.itemdes').attr('contenteditable', true).text(text);
dataActive = $(this).closest('li').attr('data-act') == 'Y' ? 'checked="checked"' : '';
ActiveOpt = '<p><label><input type="checkbox" id="active" class="filled-in" ' + dataActive + ' /><span>Active</span></label></p>';
IconOpt = '<p><i class="' + li_icon + '" id="icon_element" aria-hidden="true"></i></p>';
var datahtml = ActiveOpt + IconOpt;
modalBody.find('.modalBody').html(datahtml);
// modalBody.find('.modalBody').append(IconOpt);
$('body').on('click', '.saveChange', function() {
var textarea = $('.itemdes').text();
var appendItem = textarea;
li_element.text('').empty().append(appendItem).append(child);
// $(this).closest("li").text('').empty().append(appendItem).append(child);
ActiveOpt = '';
IconOpt = '';
// li_element = '';
});
// Function to check li data-Acive
$('body').on('change', '#active', function() {
li_element.removeAttr('data-act');
// console.log(li_element.prop('checked'));
if ($(this).prop('checked')) {
li_element.attr('data-act', 'Y');
// li_element.attr('checked','checked');
} else {
li_element.attr('data-act', 'N');
// li_element.removeAttr('checked');
}
})
});
})
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Materialized CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- Modal Trigger -->
<!-- Modal Structure -->
<div id="modal1" class="modal">
<div class="modal-content">
<h4 style="width: auto; float: left;"><i class="fa fa-pencil-square-o" aria-hidden="true"> </i></h4>
<h4 class="itemdes">Modal Header</h4>
<div class="modalBody">
<p>A bunch of text</p>
</div>
Save
</div>
</div>
<ol class="example example2">
<li data-formdesc="User" data-act="Y" data-icon="fa fa-heart">
<i class="fa fa-heart"></i>User<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Cash Withdrawal" data-act="Y" data-icon="">
<i class=""></i>Cash Withdrawal<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Branch1" data-act="Y" data-icon="fa fa-futbol-o">
<i class="fa fa-futbol-o"></i>Branch1<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol>
<li data-formdesc="Customer Centre" data-act="Y" data-icon="">
<i class=""></i>Customer Centre<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Customers Detail Listing" data-act="Y" data-icon="">
<i class=""></i>Customers Detail Listing<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
</ol>
</li>
<li data-formdesc="2 two" data-act="Y" data-icon="fa fa-linkedin">
<i class="fa fa-linkedin"></i>2 two<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol>
<li data-formdesc="Cash Withdrawal" data-act="Y" data-icon="">
<i class=""></i>Cash Withdrawal<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Till to Till Transfer" data-act="Y" data-icon="">
<i class=""></i>Till to Till Transfer<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol>
<li data-formdesc="Disbursement Voucher" data-act="Y" data-icon="">
<i class=""></i>Disbursement Voucher<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
</ol>
</li>
<li data-formdesc="Income Posting" data-act="Y" data-icon="">
<i class=""></i>Income Posting<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
</ol>
</li>
</ol>
For example, first time I edit list item 'User' to 'Users', after I clicked on save, the item text changed well. But at second time I edit another item, let's say 'Cash Withdrawal' to 'Cash Withdrawaling', after clicked Save, the item I edited change to 'Cash Withdrawaling', but list item 'Users' that I edited previously, also change to 'Cash Withdrawaling' as well.
I did not know what is incorrect with my JavaScript. How can I correct that? Thanks
At every click on .fa-pencil you add again event listeners to .saveChange and #active, using local variables like li_element, which are scoped to the callback function. This means that the second time you edit an item, two callbacks are executed, but the first still uses the previous value for li_element, thus setting the new value to the previous edited element too.
You should declare all the event listeners once, and move all the needed variables to the same level as var child.
This should work
$(document).ready(function() {
$('.modal').modal(); // modal
var child;
var li_element;
$('body').on('click', '.fa-pencil', function(e) {
var text = $(this).closest("li").clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
child = $(this).closest("li").children();
li_element = $(this).closest('li');
console.log(li_element);
var dataActive = $(this).closest('li').attr('data-act');
var li_icon = li_element.attr('data-icon');
var modal1 = $('#modal1');
var modalBody = modal1.find('.modal-content');
modalBody.find('h4.itemdes').text('');
modalBody.find('.modalBody').html('');
var modalHeader = modalBody.find('h4.itemdes').attr('contenteditable', true).text(text);
dataActive = $(this).closest('li').attr('data-act') == 'Y' ? 'checked="checked"' : '';
ActiveOpt = '<p><label><input type="checkbox" id="active" class="filled-in" ' + dataActive + ' /><span>Active</span></label></p>';
IconOpt = '<p><i class="' + li_icon + '" id="icon_element" aria-hidden="true"></i></p>';
var datahtml = ActiveOpt + IconOpt;
modalBody.find('.modalBody').html(datahtml);
// modalBody.find('.modalBody').append(IconOpt);
});
$('body').on('click', '.saveChange', function() {
var textarea = $('.itemdes').text();
var appendItem = textarea;
li_element.text('').empty().append(appendItem).append(child);
// $(this).closest("li").text('').empty().append(appendItem).append(child);
ActiveOpt = '';
IconOpt = '';
// li_element = '';
});
// Function to check li data-Acive
$('body').on('change', '#active', function() {
li_element.removeAttr('data-act');
// console.log(li_element.prop('checked'));
if ($(this).prop('checked')) {
li_element.attr('data-act', 'Y');
// li_element.attr('checked','checked');
} else {
li_element.attr('data-act', 'N');
// li_element.removeAttr('checked');
}
})
})

AngularJS: How to prevent ng-click to target child elements

I have a tree structure that contains a folder as parent and files as children, but the same folder can also contain another folder as a child. At the first time the only visible items are the folders that can be clicked to see their files.
My problem is that when I click on the parent folder the child folder gets expanded too and I want to only see the files of the clicked folder.
For example (JSFIDDLE) when I click on parent folder I don't want the child folder to be also expanded until I click on it.
This is my code (the code structure must not be changed):
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<div ng-app>
<div class="folder-group">
<span class="folder-title" ng-click="openFolder=!openFolder">
<i class="fa {{openFolder ? 'fa-chevron-down' : 'fa-chevron-right'}}"></i>
<i class="fa fa-folder-o"></i>
folder parent
</span>
<ul ng-show="openFolder">
<li>file1</li>
<li>file2</li>
<li>file3</li>
<li>file4</li>
<li class="children-folder">
<span class="folder-title" ng-click="openFolder=!openFolder">
<i class="fa {{openFolder ? 'fa-chevron-down' : 'fa-chevron-right'}}"></i>
<i class="fa fa-folder-o"></i>
folder children
</span>
<ul ng-show="openFolder">
<li>file1</li>
<li>file2</li>
<li>file3</li>
<li>file4</li>
</ul>
</li>
</ul>
</div>
</div>
This is the original template:
<span class="folder-title" ng-click="get_menu_items(folder); openFolder =! openFolder;">
<i class="fa {{openFolder ? 'fa-chevron-down' : 'fa-chevron-right'}}"></i>
<i class="fa fa-folder-o"></i>
{{ folder.name }}
</span>
<ul ng-show="openFolder">
<li class="item" ng-repeat="file in folder.files">
<label>
<input class='file-list-item' type="checkbox" name="file_map[]" value="{{ file.id }}" ng-model="file_map[file.id]" ng-click="update_selection($event)" />
<i class="fa fa-file-o"></i>
<span>{{ file.name }}</span>
</label>
</li>
<li menuitem ng-repeat="folder in folder.folders" ng-model="folder"></li>
</ul>
scope.get_menu_items = function(folder) {
folders_service.get_sub_folders(folder, false, function(folders, files) {
}, function(err, status) {
scope.handle_top_level_errors(err, status);
});
}
Just rename the ng-click for children folder
<li class="children-folder">
<span class="folder-title" ng-click="openFolder2=!openFolder2">
<i class="fa {{openFolder2 ? 'fa-chevron-down' : 'fa-chevron-right'}}"></i>
<i class="fa fa-folder-o"></i>
folder children
</span>
<ul ng-show="openFolder2">
<li>file1</li>
<li>file2</li>
<li>file3</li>
<li>file4</li>
</ul>
</li>
EDIT 2:
In your folder function,
You need to add _{{$index+1}} along with the openFolder name along with the loop such the names come up as openFolder_1, openFolder_2.. . I am unable to pin point your function with the above details
This following is just for reference purpose.
<li ng-repeat="name in names">{{openFolder}}_{{$index+1}}</li>
results in
openFolder_1
openFolder_2

Categories

Resources