I have problem when I am trying to save edited value on same index but when I am saved value its not possbile beacause edited mode not closed .
TypeScript File
` I need to save edited value in selected Command(Item).
SelectedVtucommand is String[ ] value saved in this String array.
editClick = (command: string, index: number) => {
this.logger.trace('editClick() called with command', command);
this.editingIndex = index;
this.logger.trace('editClick() called with this.editingIndex', this.editingIndex);
this.flipVtCommandSelected(command);
this.logger.trace('editClick() returning');
};
saveCommand = (command: string, index: number) => {
this.logger.trace('saveCommand() called with command, index', command, index);
this.editingIndex = -1;
this.logger.trace('saveCommand() called with this.editingIndex', this.editingIndex);
if (this.editingIndex) {
//then remove command from selted List
//this.selectedVtuCommands.splice(index, 1);
//command === LiveComponent.BLANK_STRING
// validation for blank command
if (!command || !command.trim()) {
this.showAddVtuCommandErrorMessage();
this.logger.trace('command is not valid, saveCommand() returning');
return;
}
//validation for already present command in selected list
this.selectedVtuCommands.forEach(
(selectedcommand: string) => {
if (selectedcommand === command) {
this.showAlreadyPresentVtuCommandErrorMessage();
this.logger.trace('command is already present, saveCommand() returning');
return;
}
}
);
this.selectedVtuCommands = this.selectedVtuCommands.filter(arg => arg !== command);
this.selectedVtuCommands.push(command);
this.logger.trace('command edited then add in selected VTU-Command', this.selectedVtuCommands);
}
this.logger.trace('saveCommand() returning');
}
I need to edit with save Item using HTML
`<div id="vtu-command-div">
<li *ngFor="let command of selectedVtuCommands; let commandIndex = index" class="list-group-item">
<div *ngIf="editingIndex !== commandIndex; else editingTemplate" class="mt-2 d-inline-block">
{{ command }}
</div>
<ng-template #editingTemplate>
<div id="inputdiv" *ngIf="editingIndex ===commandIndex">
<textarea id="textareadiv" class="mt-2 d-inline-block" [(ngModel)]="command"></textarea>
<button id="text-area-button-div" *ngIf="editingIndex === commandIndex" class="btn btn-secondary pull-right" (click)="saveCommand(command, commandIndex)">
<i class="fa fa-save"></i>
</button>
</div>
</ng-template>
<button *ngIf="editingIndex !== commandIndex" (click)="deleteVtuCommand(command)"
class="btn btn-secondary pull-right ml-2">
<i class="fa fa-trash"></i>
</button>
<button *ngIf="editingIndex !== commandIndex"
class="btn btn-secondary pull-right" (click)="editClick(command, commandIndex)">
<i class="fa fa-pencil" aria-hidden="true"></i>
</button>
</li>
</ul>
</div>`
I have resolved this question answer
This is output when i want to save Item on same index.
1.please find index
2.command and on that index which edited from you
saveCommand = (command: string, index: number) => {
this.logger.trace('saveCommand() called with command, index', command, index);
this.editingIndex = -1;
this.logger.trace('saveCommand() called with this.editingIndex', this.editingIndex);
if (this.editingIndex) {
//validation for blank command in selected list
if (!command || !command.trim()) {
this.showAddVtuCommandErrorMessage();
this.logger.trace('command is not valid, saveCommand() returning');
return;
}
//validation for already present command in selected list
this.selectedVtuCommands.forEach(
(selectedcommand: string) => {
if (selectedcommand === command) {
this.showAlreadyPresentVtuCommandErrorMessage();
this.logger.trace('command is already present, saveCommand() returning');
return;
}
}
);
this.selectedVtuCommands.indexOf(command);
this.selectedVtuCommands[index] = command;
this.selectedVtuCommands.forEach(
(selectedcommand: string) => {
if (selectedcommand === command) {
this.flipVtCommandSelected(command);
}
}
);
this.logger.trace('command edited then add in selected VTU-Command', this.selectedVtuCommands);
}
this.logger.trace('saveCommand() returning');
}
Related
I am doing an e-commerce project. I am currently trying to create the functionality of the quantity amount for each new added item. However, when the amount of one item altered, though it does not change the other item's quantity, when you try to alter the other item's quantity it starts from the number of the previous item's quantity.
For example, if I make the quantity of 'item1' = 3. Then if I adjust 'item2', whether I increase or decrease, it starts from 3, instead of 1.
I think I am maybe complicating it for myself I am still new to JavaScript.
const quantityIncDec = function (plus, minus) {
let quantity = 1;
plus.forEach(button => {
button.addEventListener('click', function () {
quantity++;
this.parentElement.children[1].textContent = quantity;
});
});
minus.forEach(button => {
button.addEventListener('click', function () {
if (quantity > 1) {
quantity--;
this.parentElement.children[1].textContent = quantity;
}
});
});
};
// Add to Cart Preview
btnAddCart.forEach(element => {
element.addEventListener('click', function () {
const markup = `
<li class="index-preview-list-item">
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
<div class="quantity">
<button class="btn btn-plus">
<i class="fa-solid fa-plus"></i>
</button>
<p class="quantity-value">1</p>
<button class="btn btn-minus">
<i class="fa-solid fa-minus"></i>
</button>
</div>
</div>
<button class="btn btn-delete">
<i class="fa-solid fa-trash-can"></i>
</button>
</li>
`;
clearPreviewText(previewTextCart);
cartPreviewContainer.insertAdjacentHTML('beforeend', markup);
const btnPlus = document.querySelectorAll('.btn-plus');
const btnMinus = document.querySelectorAll('.btn-minus');
quantityIncDec(btnPlus, btnMinus);
const btnDelete = document.querySelectorAll('.btn-delete');
deleteItem(btnDelete);
});
});
The let keyword is used to create a block-scoped variable. So, you will have a single instance of that variable in its block. Let's illustrate this in two examples:
let quantity = 0;
for (let button of document.querySelectorAll(".btn")) {
button.addEventListener("click", function() {
alert(++quantity);
});
}
<input class="btn" type="button" value="1">
<input class="btn" type="button" value="2">
<input class="btn" type="button" value="3">
<input class="btn" type="button" value="4">
<input class="btn" type="button" value="5">
<input class="btn" type="button" value="6">
<input class="btn" type="button" value="7">
As you can see, the counter is being updated whenever you click on a button and it does not separately keep track of each button's quantity. This is your mistake. Now, let's see a corrected example, where quantity is created in the correct block:
for (let button of document.querySelectorAll(".btn")) {
let quantity = 0;
button.addEventListener("click", function() {
alert(++quantity);
});
}
<input class="btn" type="button" value="1">
<input class="btn" type="button" value="2">
<input class="btn" type="button" value="3">
<input class="btn" type="button" value="4">
<input class="btn" type="button" value="5">
<input class="btn" type="button" value="6">
<input class="btn" type="button" value="7">
If you click on different buttons here, then you will see that each is having "its own" quantity. So, having said this, let's apply a similar fix for your code:
const quantityIncDec = function (plus, minus) {
//quantity is no longer defined here, because then it's out of the loop's
//block and its value will be shared between the buttons
plus.forEach(button => {
//Instead, we create quantity here and it will be therefore in the
//context of the "current" button
let quantity = 1;
button.addEventListener('click', function () {
quantity++;
this.parentElement.children[1].textContent = quantity;
});
});
minus.forEach(button => {
button.addEventListener('click', function () {
if (quantity > 1) {
quantity--;
this.parentElement.children[1].textContent = quantity;
}
});
});
};
// Add to Cart Preview
btnAddCart.forEach(element => {
element.addEventListener('click', function () {
const markup = `
<li class="index-preview-list-item">
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
<div class="quantity">
<button class="btn btn-plus">
<i class="fa-solid fa-plus"></i>
</button>
<p class="quantity-value">1</p>
<button class="btn btn-minus">
<i class="fa-solid fa-minus"></i>
</button>
</div>
</div>
<button class="btn btn-delete">
<i class="fa-solid fa-trash-can"></i>
</button>
</li>
`;
clearPreviewText(previewTextCart);
cartPreviewContainer.insertAdjacentHTML('beforeend', markup);
const btnPlus = document.querySelectorAll('.btn-plus');
const btnMinus = document.querySelectorAll('.btn-minus');
quantityIncDec(btnPlus, btnMinus);
const btnDelete = document.querySelectorAll('.btn-delete');
deleteItem(btnDelete);
});
});
EDIT
The solution above was ignoring that a minus button also has to work with the same quantity, so I apply a fix for it:
const quantityIncDec = function (plus, minus) {
//quantity is no longer defined here, because then it's out of the loop's
//block and its value will be shared between the buttons
let limit = Math.max(plus.length, minus.length);
for (index = 0; index < limit; index++) {
if (plus.length > index) {
let plusButton = plus[index];
plusButton.addEventListener('click', function () {
quantity++;
this.parentElement.children[1].textContent = quantity;
});
}
if (minus.length > index) {
let minusButton = minus[index];
minusButton.addEventListener('click', function () {
if (quantity > 1) {
quantity--;
this.parentElement.children[1].textContent = quantity;
}
});
}
}
};
// Add to Cart Preview
btnAddCart.forEach(element => {
element.addEventListener('click', function () {
const markup = `
<li class="index-preview-list-item">
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
<div class="quantity">
<button class="btn btn-plus">
<i class="fa-solid fa-plus"></i>
</button>
<p class="quantity-value">1</p>
<button class="btn btn-minus">
<i class="fa-solid fa-minus"></i>
</button>
</div>
</div>
<button class="btn btn-delete">
<i class="fa-solid fa-trash-can"></i>
</button>
</li>
`;
clearPreviewText(previewTextCart);
cartPreviewContainer.insertAdjacentHTML('beforeend', markup);
const btnPlus = document.querySelectorAll('.btn-plus');
const btnMinus = document.querySelectorAll('.btn-minus');
quantityIncDec(btnPlus, btnMinus);
const btnDelete = document.querySelectorAll('.btn-delete');
deleteItem(btnDelete);
});
});
I'm not sure, If I understood your question correctly. The problem in your source code is, that the only single quantity variable you are using for all of your products. But each product has it's own quantity state, therefore In your case, If you will modify quantity of one product, you will also modify initial quantity state of all another products.
Inside listener callback method, you must firstly get the previous quantity state for the current product and after that increment that value. Also another way is for example save current product quantities into array variable, and then you will need firstly find the initial quantity state from right array value, then increment and then save back modified value to that array.
// ...or ungly but most simple solution, take text content, convert to Int, then increment and store back to the element
this.parentElement.children[1].textContent = parseInt(this.parentElement.children[1].textContent)+1;
Edited answer:
// Write Javascript code!
const appDiv = document.getElementById('app');
appDiv.innerHTML = `<div id="basket">Basket</div>`;
let items = [
{
id: 24,
name: 'halabala',
qty: 10,
},
];
function Basket() {
const render = () => {
const elBasket = document.getElementById('basket');
elBasket.innerHTML = ''; // Remove all childs from previous render
// console.log(elBasket);
if (items.length) {
items.forEach((item) => {
const that = this;
const elDiv = document.createElement('div');
const elSpan = document.createElement('span');
elSpan.innerText = ' ' + item.name + ' (' + item.qty + ')';
const btnPlus = document.createElement('button');
btnPlus.innerText = '+';
btnPlus.addEventListener('click', (event) => {
event.preventDefault();
Basket().incrementItem(item.id);
});
const btnMinus = document.createElement('button');
btnMinus.innerText = '-';
btnMinus.addEventListener('click', (event) => {
event.preventDefault();
Basket().decrementItem(item.id);
});
elDiv.appendChild(btnPlus);
elDiv.appendChild(btnMinus);
elDiv.appendChild(elSpan);
elBasket.appendChild(elDiv);
});
}
};
return {
init: () => {
render();
},
addItem: (itemId, itemName, gty = 1) => {
items.push({ id: itemId, name: itemName, qty: qty });
render();
},
removeItem: (itemId) => {
items = items.filter((i) => i.id != itemId);
render();
},
incrementItem: (itemId) => {
const item = items.find((i) => i.id === itemId);
if (!item)
throw new Error('Unable to increment, because item not found!');
item.qty++;
render();
},
decrementItem: (itemId) => {
const item = items.find((i) => i.id === itemId);
if (!item)
throw new Error('Unable to decrement, because item not found!');
item.qty--;
render();
},
clearBasket: () => {
items = [];
},
};
}
Basket().init();
I'm creating a page which has multiple order buttons (One for each menu item). When an order is placed I want to call a Javascript function to change only the order button pressed rather than every button with the ID. There has to be better implementation for these function calls... Anyone?
function orderFood1(helpVal) {
if (document.getElementById("food1").innerHTML === "Order") {
document.getElementById("food1").innerHTML = "✅";
// Alert waiter
} else {
document.getElementById("food1").innerHTML = "Order";
// Cancel Request
}
}
function orderFood2(helpVal) {
if (document.getElementById("food2").innerHTML === "Order") {
document.getElementById("food2").innerHTML = "✅";
// Alert waiter
} else {
document.getElementById("food2").innerHTML = "Order";
// Cancel Request
}
}
function orderFood3(helpVal) {
if (document.getElementById("food3").innerHTML === "Order") {
document.getElementById("food3").innerHTML = "✅";
// Alert waiter
} else {
document.getElementById("food3").innerHTML = "Order";
// Cancel Request
}
}
<button type="button" id="food1" onclick="orderFood1()" class="btn btn-primary">Order</button>
<button type="button" id="food2" onclick="orderFood2()" class="btn btn-primary">Order</button>
<button type="button" id="food3" onclick="orderFood3()" class="btn btn-primary">Order</button>
They all look to do nearly the same thing, so you can use only a single function. To identify which button was clicked, you can examine the clicked button from the listener - the target of the event. Also, best to avoid inline handlers - attach the listeners properly using Javascript instead.
Since you're only inserting text, it'd be more appropriate to retrieve and assign to the textContent of the element, rather than its innerHTML.
const handleOrder = ({ target }) => {
if (target.textContent === 'Order') {
target.textContent = '✅';
console.log('Alerting waiter');
} else {
target.textContent = "Order";
console.log('Canceling request');
}
};
for (const button of document.querySelectorAll('button')) {
button.addEventListener('click', handleOrder);
}
<button type="button" class="btn btn-primary">Order</button>
<button type="button" class="btn btn-primary">Order</button>
<button type="button" class="btn btn-primary">Order</button>
I think you can create the following html code:
<button type="button" id="food1" onclick="orderFood('food1')" class="btn btn-primary">Order</button>
<button type="button" id="food2" onclick="orderFood('food2')" class="btn btn-primary">Order</button>
Which means that you use only single orderFood function, that gets the ID of the button element as a parameter.
And then your JS code could be something like this:
function orderFood(foodId) {
if (document.getElementById(foodId).innerHTML === "Order") {
document.getElementById(foodId).innerHTML = "✅";
// Alert waiter
} else {
document.getElementById(foodId).innerHTML = "Order";
// Cancel Request
}
}
I'm trying to compare user input value with JSON data.
I found some questions similar to this one, but it didn't solve my problem.
This is my code, do you know why it doesn't work.
Javascript
fetch('js/countries.json')
.then(res => res.json())
.then(data => {
function checkCountry() {
let input = document.getElementById("countryInput").value;
let country = data.find(check => check.country === "Norway");
let text;
if (input === data[country]) {
text = "Yes";
} else {
text = "No";
}
document.getElementById("alert").innerHTML = text;
}
document.getElementById("check").addEventListener("click", checkCountry);
console.log(data);
})
JSON
[{"country":"USA","active":true},
{"country":"Spain","active":true},
{"country":"Norway","active":true}]
HTML
<form action="">
<div class="input-container">
<input id="countryInput" type="text" placeholder="Country">
<i class="fas fa-search"></i>
</div>
<button id="check" type="button">CHECK</button>
</form>
This line is not good: if (input === data[country]) {
you have to check with the same mechanism as you have checked for country above...
let inputCountry = data.find(check => check.country === input);
Like this:
const data = [{"country":"USA","active":true},
{"country":"Spain","active":true},
{"country":"Norway","active":true}];
document.getElementById("check").addEventListener("click", checkCountry);
function checkCountry() {
let input = document.getElementById("countryInput").value;
let country = data.find(check => check.country === "Norway");
let inputCountry = data.find(check => check.country === input);
let text;
// You have to check with the country
if (inputCountry && input === inputCountry.country) {
text = "Yes";
} else {
text = "No";
}
console.log(text);
}
<form action="">
<div class="input-container">
<input id="countryInput" type="text" placeholder="Country">
<i class="fas fa-search"></i>
</div>
<button id="check" type="button">CHECK</button>
</form>
You can't use data[country] because data isn't key value pair collection.
It consists of objects.
Try to change resulting json from {'country': 'Spain', 'active': true}, ... to
'Spain': {active: true}, ...
Or call data element via:
if (input === data.find(el => el.country == country)) {
text = "Yes";
} else {
text = "No";
}
So I am struggling to understand where a console error is coming from. It doesn't currently break any behavior, but the error is unsettling. The error happens when I trigger a .blur() on a span that is being edited. Jquery then complains "jquery.js:1451 Uncaught TypeError: elem.getAttribute is not a function"
The directive html:
<span ng-if="!time">{{ value }}</span>
<button class="btn btn-primary delink"
ng-if="delinkable && delinkVisable"
ng-click="resource.delink()">Not speaking</button>
<span ng-if="time">{{ value | momentFormat }}</span>
<div ng-if="time && datepicker" class="dropdown" id="datepicker">
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<datetimepicker ng-model="resource.MeetingDateTime"
data-on-set-time="updateResource()"
data-datetimepicker-config="{ dropdownSelector: '#dropdown2' }">
</datetimepicker>
</ul>
<a class="dropdown-toggle" id="dropdown2" role="button" data-disabled="true"
data-toggle="dropdown" data-target="#" href>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
</div>
</a>
The relevant link functions:
function handleChanges () {
var editSpan = angular.element(element.children()[0]);
var newValue;
if (scope.time) {
newValue = dates.makeDateTime(editSpan.text());
if (newValue) {
scope.resource[scope.property] = newValue;
newValue = editSpan.text();
} else {
editSpan.text(oldValue);
newValue = editSpan.text();
scope.resource[scope.property] = dates.makeDateTime(editSpan.text());
scope.datepicker = true;
$('#dropdown2').trigger('click');
scope.$digest();
}
} else {
scope.resource[scope.property] = editSpan.text();
newValue = editSpan.text();
}
if (newValue !== oldValue) {
scope.updateResource();
compileElement();
} else {
if (scope.time) {
hideDatepicker();
}
}
}
function bindEvents () {
var editSpan = angular.element(element.children()[0]);
editSpan.on('blur', function () {
editSpan.attr('contentEditable', false);
editSpan.unbind('keydown');
editSpan.unbind('blur');
scope.editing = false;
handleChanges();
});
editSpan.on('keydown', function(event){
if (event.keyCode == 27) {
event.preventDefault();
editSpan.text(oldValue);
editSpan.blur(); //The error seems to happen after this call
} else if (event.keyCode == 13) {
editSpan.blur(); //and after this call
} else if (scope.deleteable && event.keyCode == 8) {
if (editSpan.text().length == 0 || event.ctrlKey) {
scope.delete();
}
}
});
}
So I don't know how generalizable this answer will be, but in case it is useful to you, the problem occurred because of the compile function.
Basically, compileElement was replacing the originally bound instance of the span with the freshly compiled instance, so when Jquery eventually got around to trying to rebind the click function, the element no longer existed, even though an identical span was there in it's place.
The solution was to update the values of the original span, instead of using $compile to re-compile the element.
I'm using AngularJS ng-repeat to create a list of cities. The list is being built dynamically client-side by the user. The user selects city from a list on the left side of the page, clicks the "Add City" button, and the city is added to a list on the right. The ng-repeat is in both lists, but when a city is added to the list on the right, the $index value for the list items does not update. The $index values are all zero.
Here's the ng-repeat list where the cities are added dynamically:
<div ng-repeat="(key, value) in filter.selectedCities | groupBy:'country'" class="text-left">
<div ng-repeat="(key2, value2) in value | groupBy:'state'" class="text-left">
<span class="label label-default">{{key}} </span> <span class="label label-danger" ng-show="key2.length">{{key2}} </span>
<ul class="nav nav-pills">
<li class="selectedpill" ng-repeat="city in value2">
<div class="pull-left">
<span class="indent8">{{ city.label | characters:24 :true}}</span>
</div>
<div class="pull-right">
<i class="fa fa-heart pointer" ng-click="addToCityFavs($index);" ng-class="{'maroonzheimer' : checkFavCity(city)}" ng-hide="savingCityFav" title="Add To Favorites"></i>
<i class="fa fa-spinner fa-spin" ng-show="savingCityFav"></i>
<i class="fa fa-times fa-lg pointer" ng-click="removeCity(city)" title="Remove City"></i>
</div>
</li>
</ul>
</div>
</div>
Here are the JavaScript functions used to add a city dynamically to the list:
$scope.addSelectedCity = function () {
if ($scope.selectedCity && $scope.selectedCity.value) {
$scope.addCity($scope.selectedCity);
$scope.cityValidationError = false;
} else { $scope.cityValidationError = true; }
$scope.tempSelectedCity = null;
$scope.selectedCity = null;
}
$scope.addCity = function (city) {
if (city && city.city && !$scope.checkCityExists(city)) {
$scope.filter.selectedCities.push(city);
}
}
$scope.addToCityFavs = function (index) {
var city = $scope.filter.selectedCities[index];
var exists = false;
for (var i = 0; i < $scope.filter.favs.CityList.length; i++) {
if ($scope.filter.favs.CityList[i].city.value == city.value) {
exists = true;
}
}
if (!exists) {
$scope.savingCityFav = true;
var fav = { id: 0, active: true, ruser_id: 0, city: city };
Do I need to add something to the HTML or JavaScript functions to get the ng-repeat list to update the $index value after a city has been added to the list?
I'll appreciate any help anyone can give.
Try to add track by $index to ng-repeat.
See this link for an example: https://egghead.io/lessons/angularjs-index-event-log
So it seems that the index is only needed to get the city from the array filter.selectedCities. But you don't need the index, because you can use the city directly:
ng-click="addToCityFavs(city);"
$scope.addToCityFavs = function (city) {
//no longer needed -> var city = $scope.filter.selectedCities[index];
var exists = false;