How to swap json - javascript

In my angular code on page load there are list of buttons like button 1, button 2, button 3.. etc on click of every button it shows J-SON on console the structure is same for all buttons but the values vary. There are two more buttons on page on up and down.
My question is if button 2 is selected and i click on up button then the position of button 2 should moved up to button 1 for that we have use one attribute in j-son but problem m facing is that how should i swap whole j-son like how to swap position of button 2 to button 1 and vice-versa for down arrow
searched for swapping on google but it showing items in array to swap. i want whole j-son to swap
up(){
exchange(this.jsondata,up,up+1);
}
private exchange(array: any, x: any, y: any) {
const temp = array[x];
array[x] = array[y];
array[y] = temp;
return array;
}
it should change the position of buttons on click of up down buttons

If what you want is swapping two elements in an array, your exchange function seems ok.
But you are calling it with only 2 parameters : up(up, up+1) while your function takes 3 parameters :
the array where the items are
the first item
the second item
If your buttons were in an array named myButtons, you would probably want to call it that way :
up(myButtons, up, up+1);
Side notes :
be careful what you're naming your parameters. Array is a global JavaScript object. It's not a good practice to use that name for a variable.
up is obviously the name of a function and a variable. That is kind of confusing.
your function returns the array that was passed as a paramter. That is not necessary since arrays are passed as references. You can make your function immutable and have it return a different array. Or modify the reference and not return anything.

Related

Understanding GSAP accordion

I'm trying to understand this piece:
https://codepen.io/GreenSock/pen/RwVgEgZ
The hard thing for me is to understand the select property. AFAIK, this is a property of a <select> HTML element, that it is no present in this HTML. And a particular use of forEach.
This is the JS as I understand:
// toArray GSAP tool
// https://greensock.com/docs/v3/GSAP/UtilityMethods/toArray()
// Store an array with .accordion-group elements
let groups = gsap.utils.toArray(".accordion-group");
// Store an array with .accordion-menu elements
let menus = gsap.utils.toArray(".accordion-menu");
// Apply createAnimation(element) for each array element
// This creates animations for each .accordion-group
// and store it in a variable
let animations = groups.map(createAnimation);
// Add click event listener to each .accordion-menu
// that fires playAnimation(selected) on click
menus.forEach(menu => {
menu.addEventListener("click", () => playAnimation(menu));
});
//
function playAnimation(selected) {
// I don't undestand this particular use of forEach
// what means animate => animate(selected)?
// what means selected? I search this property on MDN web docs with no luck
animations.forEach(animate => animate(selected))
}
// CreateAnimation function
function createAnimation(element) {
// Create colections of .accordion-menu and .accordion-content
let menu = element.querySelector(".accordion-menu");
let box = element.querySelector(".accordion-content");
// GSAP initial set height of .accordion-content to auto
gsap.set(box, { height: "auto"})
// GSAP tween reversed. I have no problem with this
let tween = gsap.from(box, {
height: 0,
duration: 0.5,
ease: "power1.inOut"
}).reverse();
// CreateAnimation() returns the tween reversed if it is not selected
return function(selected) {
// Ternary operator.
// Store true in the reverse variable if menu is not selected
// Get !tween.reversed() (This means true if tween is not reversed or false if it is reversed) and store it in reversed variable.
let reversed = selected !== menu ? true : !tween.reversed();
// return tween reversed or not reversed regarding reversed variable
tween.reversed(reversed);
}
}
In short, what I want to know is: what does this mean: animate => animate(selected)? What means selected? I searched this property on MDN web docs with no luck.
While chliang is not wrong, I feel like explaining the process of what's going on in general is valuable as I think your understanding is not quite correct.
Here's the steps of what happens when the JS is ran:
The DOM elements are selected.
The groups are looped through and an animation for each group that animates the height of that specific group is created. This animation will be re-used each time that the group is animated (i.e. a new animation will not be created, only the state of this animation will be changed — this is a good technique of animating efficiently).
With that being said, what is actually returned is not a reference to the animation itself but rather a function that controls the reversed state of the animation. It'd probably help to look at the .reversed() documentation.
The menu items are looped through, adding a click event listener to each. The event listener for each menu item passes in that menu item to the function that was returned in the last step. Inside of the function (returned from the last step), if the menu item is the same as the one that is clicked, the reversed state for that animation is set to the opposite of what it currently is, usually being set to true, meaning the animation will play forwards. However if it's the same one that's clicked and it's reversed state is already false this means that it's already opened or opening, so its reversed state will be changed false.
For all other animations, the reversed state will be set to true, meaning it will play backwards if its progress is not 0. It will do nothing if its progress is 0.
To be clear, the HTML <select> element is not being used and is unrelated to the demo. It achieves similar behavior but cannot be customized to behave like this accordion.
With all of that being said, I probably would have written this code in a different way to be more readable, like this.
Let me know if you have any more questions.
First of All "animations" is an Array which has 5 functions .
animations.forEach
will pass every function to the brackets next to it,suppose the first function is fun1 .
selected is the param of The Function "playAnimation" , in fact selected is one menu of the menus ,then passed to the function eg. fun1 , fun1(selected) triggers.
replace fun1 to animate .

Ember.js - Remove Only One instance of Object with removeObject

Explanation
I have a very simple calorie tracking app that uses the Nutritionix API to search for food items based on the user's input. The results are added to a results array, which is then displayed to the user. When a user clicks the "Add" button next to one of these items, the calories are added to a counter, and the food itself is added to a todaysFood array (using Ember's pushObject). This is then used to display which food the user has consumed today in a separate table.
When a user clicks the remove button next to one of the todaysFood items, it triggers an action, removeItem, and passes the index of the item clicked to removeItem. This index is used inside of Ember's removeObject to remove the item from the todaysFood array, and thus update the view (remove that item from the list and its calories from the counter).
Problem
When more than one of the same item are added to todaysFood, clicking remove on just one of those items removes ALL of the instances from todaysFood, and the view. This makes sense to me now, because of the docs' example:
var cities = ['Chicago', 'Berlin', 'Lima', 'Chicago'];
cities.removeObject('Chicago'); // ['Berlin', 'Lima']
cities.removeObject('Lima'); // ['Berlin']
cities.removeObject('Tokyo') // ['Berlin']
However, it also only removes the calories of ONE item, not all instances.
So, the question is: How do I remove only ONE instance of that item when remove is clicked? I.e., if two tacos are added, and I click remove on one, I only want that ONE to be removed (from the list and the calories).
Here is my removeItem action:
removeItem(index) {
var self = this;
// Store property paths for easy access
let todaysPath = this.get('healthData').todaysFood;
let caloriesPath = 'healthData.calories';
this.set(caloriesPath, this.get(caloriesPath) - Math.round(todaysPath[index].fields.nf_calories));
todaysPath.removeObject(todaysPath[index]);
}
Disclaimer
I'm aware that I may not be handling this correctly at all. I'm open to any suggestions to make this better. Thanks!
You have index of object to remove so you can try using removeAt() method:
todaysPath.removeAt(index);

Javascript delete than splice

I am working on javascript project where I have 2 arrays 1. elements 2. elementsOrder ; elementsOrder array contains the names of each element, and elements array contains all properties of each element. When I want to delete one element from each array I do it with "delete" build in function, but it doesn't deletes element only sets it to Undefined, so than I use splice method to push out those undefined elements, but it doesn't work.
the is the source:
var s1 = elementsOrder.indexOf(id);
delete elements[s1];
delete elementsOrder[s1];
it does the job and sets elements one by one "undefined" smoothly, but when I do:
var s1 = elementsOrder.indexOf(id);
delete elements[s1];
delete elementsOrder[s1];
elements.splice(s1, 1);
elementsOrder.splice(s1, 1);
using simply splice methods don't work:
var s1 = elementsOrder.indexOf(id);
elements.splice(s1, 1);
elementsOrder.splice(s1, 1);
I use this piece of code in my Javascript Canvas project to animate some canvas objects, so I can easily see when "delete" works smoothly and "undefines" elements one by one, and splice doesn't works so smoothly and doesn't puts out elements one by one
Please see http://jsfiddle.net/7ZuuZ/ pay atantion to function animate, third function from bottom
Why not just splice in the first place?
var s1 = elementsOrder.indexOf(id);
elements.splice(s1,1);
elementsOrder.splice(s1,1);
There is no need to delete here.

Javascript/jQuery Id check to drive numbering function with validation

I need help with a loop... it's probably simple but I'm having difficulty coding it up.
Basically, I need to check existing Ids for their number so I can create a unique id with a different number. They're named like this: id="poly'+i'" in sequence with my function where i is equal to the number of existing elements. Example: Array 1, Array 2, Array 3 corresponding with i=1 for the creation of Array 1, i=2 for Array 2, etc.
Right now i is based on the total number of existing elements, and my "CreateNew" function is driven off x=i+1 (so the example above, the new element will be named Array 4). The problem is that if you delete one of the middle numbers, the "Create" function will duplicate the high number. i.e. Array 1, 2, 3 delete 2, create new-> Array 1, 3, 3.
I need an if() statement to check if the array already exists then a for() loop to cycle through all i's until it validates. Not sure how to code this up.
The code I'm trying to correct is below (note I did not write this originally, I'm simply trying to correct it with my minimal JS skills):
function NewPanel() {
var i = numberOfPanels.toString();
var x = (parseInt(i)+1).toString();
$('#items').append('<div onclick="polygonNameSelected(event)" class="polygonName" id="poly'+i+'"> Array '+ x +' </div>');
$('div[id*=poly]').removeClass('selected');
$('#poly'+i).addClass('selected');
$('#poly'+i).click(function() {
selectedPolygon = i;
$('div[id*=poly]').removeClass('selected');
$(this).addClass('selected');
});
}
THANK YOU! :)
Please clarify "The problem is that if you delete one of the middle numbers, ". What do you mean by delete? Anyway, the simplest solution is to create two arrays. Both arrays will have the same created id's. Whenever an id is created in the first array, an id will be added to the second array. So when it is deleted from first array, check your second array's highest value and then create this id in first array. I hope this did not confuse you.
Well it is hard to tell why you cannot just splice the array down. It seems to me there is a lot of extra logic involved in the tracking of element numbers. In other words, aside from the index being the same, the ids become the same as well as other attributes due to the overlapping 1, 3, 3 (from the example). If this is not the case then my assumption is incorrect.
Based on that assumption, when I encounter a situation where I want to ensure that the index created will always be an appending one, I usually take the same approach as I would with a database primary key. I set up a field:
var primaryKeyAutoInc = 0;
And every time I "create" or add an element to the data store (in this case an array) I copy the current value of the key as it's index and then increment the primaryKeyAutoInc value. This allows for the guaranteed unique indexing which I am assuming you are going for. Moreover, not only will deletes not affect future data creation, the saved key index can be used as an accessor.

SQLite: issue with SELECT * FROM Tble where?

I am working offline with SQLite, Javascript and Chrome
In my main page (main.html), I have two div: <div id="menuLeft"> that contains the list of items name with buttons to edit each item, and
<div id="content">
The list of item is written as follows:
<li>ItemName1
<div id="idItem1" class="editItem_btn">
<img src="btn_edit.png">`
</div>
</li>
In main.html, I have the following code:
$("#menuLeft").delegate(".editItem_btn", "click", function(e0)
{
e0.preventDefault();
var editItemId = $(this).attr("id");
editItemId = parseInt(editItemId);
var url="edititem.html"
$("#content").load(url,function(){
loadRecord(editItemId);`
});
});
When I click on the edit button of a given Item, the id of the Item is first retrieved from the id of the div around the edit button. Then I load the page edititem.html content. On success, I run the function loadRecord(editItemId), where loadRecord(i) is contained in edititem.html:
function loadRecord(j)
{
var item = dataset.item(j);
idItem.value = item['id'];
ItemName.value = item['ItemName'];
dateStart.value = item['dateStart'];
dateEnd.value = item['dateEnd'];
notes.value = item['notes'];
}
This function enables to display the parameters of Item (id, ItemName....) contained in the database.
Here is my problem, the code works but in a weird way meaning that if I click on the edit button of Item1, the parameters of Item2 are displayed. Same thing if I click on edit Item2, parameters of Item3 are displayed.
I then replaced:
var item = dataset.item(j);
with:
var item = dataset.item(j-1);
and that works. But I need to understand why it's behaving like that, and why I need to use (j-1). I placed some alert() in the jquery code to check that I have the right editItemId number, and in the function loadRecord(j). The right id number is retrieved after the click and the right id number is passed to the function. I have no idea what's the bug here!
Without seeing the sql side of things, and how that data is passed back to your script it's impossible to tell you exactly what's happening, but this is simply a case of some lists being 0 based and some lists being 1 based. For example, arrays are generally 0 based (unless you specifically create them a different way), but $("#id").each(function(Index)... is 1 based. You just have to know what you're working with and occasionally do as you have found and use -1 or +1 when relevant.
While I'm not familiar with the intricacies of SQLite, I suspect that dataset.item(j):
is accepting a 0-based index
that you are passing in the record_id (which in itself is not actually an array index)
and that the record_id for the dataset you are testing just happens to be the index + 1 (meaning you're getting lucky right now and that it will probably change when the next dataset is loaded).
I would check to see if there's an equivalent for dataset.item(j) which accepts a record_id and not an index. Otherwise, you'll probably want to store the index of the record somewhere in the record itself to be able to pass it to your loadRecord function.
Hope this helps,
Pete

Categories