Im trying to achieve this piece of code but in my console it says thing is null which is weird because when I look in the console, sessionStorage isn't empty...
$(".btn-alert").click(function(){
var identifierOfSpan = $(this > "span").text();
for(var prop in sessionStorage){
var thing = JSON.parse(sessionStorage.getItem(prop))
if(thing.id == identifierOfSpan){
sessionStorage.removeItem(prop);
}
}
$(this).closest(".voyages").remove();
if(sessionStorage.length == 0){
alert("Message!");
location.href="reservation.html"
}
});
the button is supposed to delete the div and the sessionStorage item which looks like this
Html :
<div class="voyages">
<button class="btn btn-alert btn-md mr-2" tabindex="-1">delete the flight</button>
<span>ID : 4224762</span>
<div class="infos">
<img src="img/angleterre.jpg" alt="maroc">
<div>
<ul>
<li><h5>Angleterre, Londres (LON)</h5></li>
<li><h5>2 adulte(s)</h5></li>
<li><h5> Aucun enfants </h5></li>
<li><h5>Type : Couple</h5></li>
</ul>
</div>
</div>
<hr>
<h3>Options</h3>
<ul>
<li>voiture : 0</li>
<li>Hotel : 0 </li>
</ul>
<hr>
<h3>Prix :3713$</h3>
If I'm reading your question correctly, you want to...
Click on a button
Find the first sibling <span> element and parse a number out of its text content
Remove all sessionStorage items (JSON serialized objects) with matching id properties
For the ID, I highly recommend adding some data directly to the <button> to help you identify the right record. If you can, try something like
<button class="btn btn-alert btn-md mr-2" data-voyage="4224762"...
Try something like this
$('.btn-alert').on('click', function() {
const btn = $(this)
const id = btn.data('voyage')
// or, if you cannot add the "data-voyage" attribute
const id = btn.next('span').text().match(/\d+$/)[0]
// for index-based removal, start at the end and work backwards
for (let i = sessionStorage.length -1; i >= 0; i--) {
let key = sessionStorage.key(i)
let thing = JSON.parse(sessionStorage.getItem(key))
if (thing.id == id) {
sessionStorage.removeItem(key)
}
}
// and the rest of your code
btn.closest(".voyages").remove();
if(sessionStorage.length === 0) {
alert("Message!");
location.href = 'reservation.html'
}
})
The problem with using a for..in loop on sessionStorage is that you not only get any item keys added but also
length
key
getItem
setItem
removeItem
clear
Related
I'm making a task board project.
Must say I'm using only HTML, CSS, JS, and nothing else right now.
I'm making a fade-in effect to the newly added note (ul element), and I would like to delete the fade-in class from the previously added note.
this is a chunk of my code that displays the note inside the div.
function displayAllTasks(allTasks){
taskNotesDiv.innerHTML = "";
for(const task of allTasks){
const index = allTasks.indexOf(task);
const note = `
<div class"noteDiv">
<ul class="fadeInNote">
<button type="button" onclick="deleteTask(${index})">
<i class="fa-solid fa-trash deleteButton"></i>
</button>
<li>Task: ${task.task}</li>
<li>Description: ${task.textArea}</li>
<li>Date: ${task.date}</li>
<li>Time: ${task.time}</li>
</ul>
</div>
`
taskNotesDiv.innerHTML += note;
}
}
I tried already another function to delete it but with no success.
any help would be appreciated!
There can be multiple approaches, but my approach is to create element using document.createElement . The modified JS will become:
function displayAllTasks(allTasks) {
last_ul = null; // store the last ul element added
taskNotesDiv.innerHTML = "";
for (const task of allTasks) {
const index = allTasks.indexOf(task);
let noteDiv = document.createElement('div');
noteDiv.classList.add('noteDiv');
note_ul = document.createElement('ul');
note_ul.classList.add('fadeInNote');
note_ul.innerHTML = `
<button type="button" onclick="deleteTask(${index})">
<i class="fa-solid fa-trash deleteButton"></i>
</button>
<li>Task: ${task.task}</li>
<li>Description: ${task.textArea}</li>
<li>Date: ${task.date}</li>
<li>Time: ${task.time}</li>`
noteDiv.appendChild(note_ul);
// if it is not the first element, then remove the class from previous
if (last_ul != null) {
last_ul.classList.remove('fadeInNote');
}
last_ul = note_ul; // this becomes previous for next iteration
taskNotesDiv.appendChild(noteDiv);
}
// remove class of the last element
if (last_ul != null) {
last_ul.classList.remove('fadeInNote');
}
}
In my application I have saved the data when we click on it(we can add the multiple data by entering some data and save the multiple data by clicking the save button).
.component.html
<ng-container *ngFor="let categoryDetail of selectedCategoryDetails">
<div class="__header">
<div>
<b>{{ categoryDetail.category }}</b>
</div>
</div>
<div
class="clinical-note__category__details"
*ngIf="categoryDetail.showDetails">
<ul>
<li class="habit-list"
*ngFor="let habits of categoryDetail.habitDetails" >
<div class="target-details">
<b>{{ clinicalNoteLabels.target }}: </b
><span class="habit-list__value">{{ habits.target }}</span>
</div>
</li>
</ul>
<div class="habit-footer">
<span class="m-l-10"
[popoverOnHover]="false"
type="button"
[popover]="customHabitPopovers"><i class="fa fa-trash-o" ></i> Delete</span>
</div>
<div class="clinical-note__popoverdelete">
<popover-content #customHabitPopovers [closeOnClickOutside]="true">
<h5>Do you want to delete this habit?</h5>
<button
class="btn-primary clinical-note__save" (click)="deletedata(habits);customHabitPopovers.hide()">yes </button>
</popover-content></div>
</div>
</ng-container>
In the above code when we click on delete button it will show some popup having buttons yes(implemented in above code) and now so my requirement is when we clcik on yes button in from the popover it has to delete the particular one.
.component.ts
public saveHealthyHabits() {
let isCategoryExist = false;
let categoryDetails = {
category: this.clinicalNoteForm.controls.category.value,
habitDetails: this.healthyHabits.value,
showDetails: true,
};
if (this.customHabitList.length) {
categoryDetails.habitDetails = categoryDetails.habitDetails.concat(
this.customHabitList
);
this.customHabitList = [];
}
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
if (selectedCategory.category === categoryDetails.category) {
isCategoryExist = true;
selectedCategory.habitDetails = selectedCategory.habitDetails.concat(
categoryDetails.habitDetails
);
}
});
}
if (!this.selectedCategoryDetails || !isCategoryExist) {
this.selectedCategoryDetails.push(categoryDetails);
}
this.clinicalNoteForm.patchValue({
category: null,
});
this.healthyHabits.clear();
public deletedata(habits){
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
if (selectedCategory.category ==categoryDetails.category) {
isCategoryExist = true;
this.selectedCategoryDetails.splice(habits, 1);
}
});
}
}
The above code I have written is for saving the data(we can enter multiple data and save multiple )
Like the above I have to delete the particular one when we click on yes button from the popover.
Can anyone help me on the same
If you're iterating in your html like:
<... *ngFor="let categoryDetails of selectedCategoryDetails" ...>
and your button with deletedata() is in the scope of ngFor, you can:
Change your iteration to include index of an item and trackBy function for updating the array in view:
<... *ngFor="let categoryDetails of selectedCategoryDetails; let i = index; trackBy: trackByFn" ...>
On the button click pass the index to deletedata() method like:
deletedata(index)
Create your deletedata method like:
deletedata(index:number){
this.selectedCategoryDetails.splice(index, 1);
// other code here, like calling api
// to update the selectedCategoryDetails source
// etc.
}
Create trackByFn method like:
trackByFn(index,item){
return index;
}
EDIT: Without index
If you want to iterate over selectedCategoryDetails in the ts file, without using ngFor with index in your html, you can have your deletedata like this:
deletedata(categoryDetails:any){
for (let i = this.selectedCategoryDetails.length - 1; i >= 0; i--) {
if (this.selectedCategoryDetails[i] === categoryDetails.category) {
this.selectedCategoryDetails.splice(i, 1);
}
}
}
It will iterate over selectedCategoryDetails backwards and remove the categoryDetails if it finds it in the array of objects.
Now, you only need to pass the categoryDetails to deletedata in your html:
(click)="deletedata(categoryDetails);customHabitPopovers.hide()"
I use WordPress. I have an audio player on my site. When a user clicks the play button on an individual song, it will play the song. The post ID is how the player determines which song to play.
So in the DIV that wraps the button tag, I assign an attribute: data-id which is the post id of the song. My app then grabs the MP3 file that is associated with that post ID. Simple.
My play button tag is essentially this:
<div class="item item-action" data-id="1161">
<button class="btn-playpause"></button>
</div>
The important parts of my player.js file that handles the click event and plays the song is below:
Simulate the play button
// simulate the play btn
$(document).on('click.btn', '.btn-playpause, .btn-queque', function(e){
e.stopPropagation();
var self = $(this),
item = $(this).closest('.item'),
id = item.attr('data-id'),
type = item.data('user-id') ? 'user' : 'post',
play = true;
if(!player){
getItem(id, type).done(function(obj){
if(obj.status == 'success'){
mep.mepPlaylistTracks = obj.tracks;
initPlayer();
player && player.mepSelect(0, true);
}
});
return;
}
if(self.is('.btn-queque')){
play = false;
self.parent().dropdown('toggle');
}
if( self.hasClass('is-playing') ){
self.removeClass('is-playing');
player.pause();
}else{
var index = player.find(id);
if( index !== -1){
var track = player.mepGetCurrentTrack();
if(track && track.id == id && !play) return;
player.mepSelect(index, true);
}else{
getItem(id, type).done(function(obj){
if(obj.status == 'success'){
addToPlay(obj.tracks, play);
}
});
}
}
});
getItem() function
function getItem(id, type){
return $.ajax({
type : "post",
dataType : "json",
url : ajax.ajax_url,
data : {action: "ajax_music", id : id, type: type, nonce: ajax.nonce}
});
}
addToPlay() function
function addToPlay(obj, play){
if(obj.length == 1){
player.mepAdd( obj[0], play );
}else if(obj.length > 1){
if(play){
player.options.mepPlaylistTracks = obj;
player.updatemepList();
player.mepSelect(0, true);
}else{
for(var i=0; i<obj.length; i++){
player.mepAdd( obj[i] );
}
}
}
}
You can see that once I click the play button, depending on a condition, it fires the getItem() function. getItem() takes the data-id attribute defined earlier as the id variable and begins to play the song.
The addToPlay() function will add another song to the playlist if there is already an instance of the player open. And when a user clicks another play button, it will add that new song to the list and begin to play that song.
Is it possible to modify this code so that I can add multiple data-id values to my button code so that my script will recognize there is more than one song id and add those to my playlist, using the addToPlay() function?
I'd like to do something like this
<div class="item item-action" data-id="1161, 1288, 1456">
<button class="btn-playpause"></button>
</div>
The reason I want to do this, is I would like to add a feature that will allow my users to Play All Songs on the current page they're viewing. Some of our pages, like the catalog page, displays dozens of songs that fit a certain criteria and I'd like the option to play all songs on the page.
Can anyone help push me in the right direction?
Thanks.
You could store a JSON encoded array in the data-id tag. Like:
<div class="item item-action" data-id='[1161, 1288, 1456]'>
<button class="btn-playpause"></button>
</div>
Then you can parse the array, and loop over its contents, adding each id to the queue.
See an example of parsing here: https://gist.github.com/charliepark/4266921
Here I present a alternative method.
In your markup, you can set the data-id='[1234] attribute as an encoded array. You can then collect those properties and set them as the data id property on a given element using jQuery as I illustrate here:
let someElement = $('.item');
let setItems = someElement.data('id');
let thisItem = someElement.attr('data-id');
IMPORTANT: the someElement.data('id') returns the same as the someElement.attr('data-id') (except as a string) IF nothing for that element has been set with someElement.data('id',[567,890]); which sets the property id for someElement. So, once set that way
let x = someElement.data('id'); // returns the array 567,890
let org = someElement.attr('data-id'); // still returns the [1234]
This code illustrates:
let someElement = $('.item').first();
let setItems = someElement.data('id');
let thisItemS = someElement.attr('data-id');
// make an array of the string
let thisItem = JSON.parse(thisItemS);
console.log(typeof setItems, setItems, typeof thisItemS, thisItemS, typeof thisItem, thisItem);
someElement.data('id', [567, 890]);
let x = someElement.data('id'); // returns and gets the array 567,890
let org = JSON.parse(someElement.attr('data-id')); // still returns the string [1234] made into an array
// merge with no duplicates, in the other code I used .map()
let z = Array.from(new Set(x.concat(org)));
console.log(x, org, z);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class='item' data-id='[1234]'>me the item</div>
This code show a set of elements using the concepts introduced above plus:
Set some check boxes for selection
Get the values (all)
Get the values (checkbox checked)
You can combine any of this for your original purpose, but you will need to manage that addition of new items values (and subsequently how to remove perhaps) on a given element. You might even add to a <select> element so the user then can pick some to remove perhaps...
function showPicks(choicedata) {
let ul = $('#choices').append('<ul />');
//ul.remove('li');
ul.html('empty');
ul.text('choices:');
$.each(choicedata, function(index, choice) {
let c = $('<li/>').html(choice);
ul.append(c);
});
}
$(function() {
let mydata = $('.item').map(function() {
return $(this).data('id');
}).get();
$('.all-items').data("id", mydata);
showPicks(mydata); //now do what is desired
});
$('item.item-action').filter(':not(".some-items")')
.on('click', '.btn-playpause', function() {
let setItems = $(this).closest('.item').data('id');
let thisItem = $(this).closest('.item').attr('data-id');
// do what you wish here, I show them
showPicks(setItems);
});
$('.some-items').on('click', '.btn-playpause', function(event) {
let mydata = $('.item-select').filter(':checked')
.add(this) // set an additional one from the button
.closest('.item')
.map(function() {
return $(this).data('id');
}).get();
$(event.delegatedTarget).data("id", mydata);
let setItems = $(event.delegatedTarget).data('id');
// the original pick
let thisItem = $(event.delegatedTarget).attr('data-id');
// do what you wish here
showPicks(mydata);
});
.btn-playpause {
height: 2em;
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="item item-action" data-id="[1161]">
<button class="btn-playpause" type="button"></button>
<input type="checkbox" class="item-select" />
</div>
<div class="item item-action" data-id="[1163]">
<button class="btn-playpause"></button>
<input type="checkbox" class="item-select" />
</div>
<div class="item item-action" data-id="[9961,7744]">
<button class="btn-playpause" type="button"></button>
<input type="checkbox" class="item-select" />
</div>
<div class="item item-action all-items" data-id="[42]">
<button class="btn-playpause" type="button">Play All</button>
</div>
<div class="item item-action some-items" data-id="[95]">
<button class="btn-playpause" type="button">Play selected</button>
</div>
<div id="choices">none</div>
I have little problem with my code. I push the value of an input in an empty array, and i display the value in a html list with a remove button.
But when i remove the value in html, the array still holds the value. I used arr.splice(0, 1) but it doesn't remove the specific value. Example:
My html list looks like:
v1
v2
v3
My array after the list is filled:
array = [v1, v2, v3]
When i remove v2 in html my array doesn't changes. I'm new to JavaScript.
My code in JSBin or JSFiddle.
im sorry my english is not very nice
https://jsfiddle.net/15mdjdpa/
var taches = [];
var saisie;
var ecran;
var liste;
var organiz;
var j= 0;
function run(){
saisie= document.getElementById('champ').value;
taches.push(saisie);
ecran = document.getElementById('afficheur');
var liste = document.getElementById('listes');
console.log("taches :", taches);
var li = document.createElement('li');
li.setAttribute("id", "lisupr");
var btn = document.createElement('Button');
btn.textContent="X";
btn.addEventListener("click",function supr (){
liste.removeChild(li);
taches.splice(0,1);
console.log("tableau taches: "+ taches);
} );
li.innerText= saisie + " "+" ";
console.log("saisie "+saisie);
li.appendChild(btn);
liste.appendChild(li);
}
<input type ="text" id="champ" onfocus="javascript:this.value=''" class="form-control ">
<button type="button" onclick ="run()" class="btn btn-primary" >send</button>
<div id="afficheur"><h4> list : </h4>
<ul id="listes"> </ul>
</div>
If you want to remove v2 from array, do like this.
var index = array.indexOf(v2);
if(index != -1) array.splice(index,1);
I'd rewrite this code using jQuery. I'd remove all the ids - you can make the edits relative to the button being clicked. Which would let you have more than one of these on a page, among other things.
HTML:
<div class="module">
<input class="item" />
<button type="button" class="btn btn-primary js-add">add</button>
<ul class="list"></ul>
</div>
Here's the script:
var list = [],
addToList = function(target,item){
list.push(item);
target
.append(
$('<li>')
.html(item)
.append(
$('<button>')
.addClass('js-delete m-l')
.html('X')
)
)
}
$('.js-add').click( function(){
var parent = $(this).parent(),
item = parent.find('input.item');
addToList(parent.find('ul.list'),item.val());
item.val('');
})
$('.module').on( 'click', '.js-delete', function(){
var parent = $(this).parent(),
index = $('li').index( parent );
list.splice(index,1);
parent.remove();
console.log(list);
})
Actually, if you want to make it so you can add multiple lists, you actually need to nest the 'list' array in an object or array, and have something reference it, probably inside the module div.
Your issue is what Angular does automatically - without all the management. It binds the html content to the json array so all you need to do is change the array value, or delete it. The HTML would immediately reflect the change.
Here's a jsfiddle:
https://jsfiddle.net/mckinleymedia/yducyt83/
I have a poll application, in which a user can vote for an option in a given poll. in the html template, i use ng-show to show weather the user has voted for this option or this poll or if its an unvoted poll for the user:
<div data-ng-repeat="option in poll.poll_options" class="list-group-item">
<span data-ng-if="option.option_thumb == '2'" class="glyphicon glyphicon-thumbs-up"></span>
<span data-ng-if="option.option_thumb == '1'" class="glyphicon glyphicon-thumbs-down"></span>
<div data-ng-show="optionVoted(option,authentication.user._id)">
<span data-ng-bind="option.option_text"></span>
</div>
<div data-ng-hide="optionVoted(option,authentication.user._id)">
<div data-ng-show="pollVoted(poll._id,votes)">
<a data-ng-click="updateVote()">
<span data-ng-bind="option.option_text"></span> - update
</a>
</div>
<div data-ng-hide="pollVoted(poll._id,votes)">
<a data-ng-click="createVote(poll,option,authentication.user._id,$index)">
<span data-ng-bind="option.option_text"></span> - new
</a>
</div>
</div>
<span class="option-votes"> - {{option.votes.length}}</span>
</div>
these are the above mentioned functions to determine if the option / poll has been voted by the user:
// check if option is voted
$scope.optionVoted = function(option,userId){
for (var i = 0; i < option.votes.length; i++){
if (option.votes[i].user === userId){
return true;
}
}
};
//check if poll is voted
$scope.pollVoted = function(pollId,votes){
for (var i = 0; i < votes.length; i++){
if (votes[i].poll === pollId){
return true;
}
}
}
and here is the function to create a new vote:
// create a vote
$scope.createVote = function(poll,option,userId,index){
var vote = new Votes({
user:userId,
poll:poll._id,
poll_option:option._id
});
vote.poll_option_id = option._id;
vote.$save(function(vote){
option.votes.push(vote);
$scope.$apply();
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
}
what happens on the front end, is that the option which has been now voted is updated (not showing an a tag anymore). what i need, is that the other options in the poll will update as well, and now instead of create() they will show update(), without refreshing the page.
how can I get the other html DOM elements of options in the poll to update?
In html, replace the functions in ng-show by an object property :
ng-show="option.voted", for example.
and update option.voted in createVote function.
(adapt this with userId etc.)
Make sure you are pushing the new vote onto the correct object in the scope. It looks like you are displaying data from $scope.poll.poll_options in your view, but you are adding to options.votes in your createVote function.