I have a table of data that is rendered from an object. Specifically, each row of the table is a value from the array.
I need to be able to move the object up or down in the array, depending on the button clicked.
var obj = [{
"RuleDetailID": "11624",
"AttributeValue": "172",
"Value": "Account Manager",
"IsValueRetired": "0"
}, {
"RuleDetailID": "11626",
"AttributeValue": "686",
"Value": "Agent",
"IsValueRetired": "0"
}, {
"RuleDetailID": "11625",
"AttributeValue": "180",
"Value": "Analyst",
"IsValueRetired": "0"
}, {
"RuleDetailID": "11629",
"AttributeValue": "807",
"Value": "Individual Contributor",
"IsValueRetired": "0"
}, {
"RuleDetailID": "11627",
"AttributeValue": "690",
"Value": "Senior Agent",
"IsValueRetired": "0"
}];
// Exmaple only, just rendering a table
function renderExample() {
var table = '';
for (var key in obj) {
table += "<tr><td>" + obj[key].Value + "</td><td>Move Up</td><td></td><td>Move Down</td></tr>";
}
return table;
}
// Move the object in the array up or down
function move(value, positionChange) {
// On run, move the object in the array up or down respectivly.
}
<table>
<tbody id="example">
<script>
document.write(renderExample())
</script>
</tbody>
</table>
Can this be done with something like lodash or is it more of a manual approach? I tried by getting the index of the clicked item and then doing +1 or -1 accordingly to give me the new index. However, I wasn't sure what to do at that point since another item would already exist at that index.
How can I go about achieving this? Not looking for a jQuery approach, javascript or a library such as lodash only.
You can use array.splice twice, first to remove the item you want to move, and then to insert it into the new position
var data = [1,2,3,4,5];
function moveItem(from, to) {
// remove `from` item and store it
var f = data.splice(from, 1)[0];
// insert stored item into position `to`
data.splice(to, 0, f);
}
moveItem(0, 2);
console.log(data);
You can also use an old-school swap mechanism:
function move(value, positionChange) {
// On run, move the object in the array up or down respectivly.
for (var i = 0; i < obj.length; i++) {
if (obj[i].RuleDetailID == positionChange) {
var newIndex = value === 'up' ? i - 1 : i + 1;
if (newIndex >= obj.length || newIndex < 0) return;
var temp = obj[i];
obj[i] = obj[newIndex];
obj[newIndex] = temp;
document.getElementById('example').innerHTML = renderExample();
}
}
}
Related
This is new question that is rewritten using javascript/jQuery of this thread because i can't do this in MySQL directly query.
MySQL Select id from to and exclude beginning and ending id
So question is simple:
I have array that have received from MySQL query into javascript array:
var array = ["m2", "1", "2", "11", "12", "m4", "m3", "m5", "17", "m1"];
And need function that accept parameter from what array value to show. For example:
function showCategories(marker){
}
So in above example if i call showCategories("m2"); i need to get this:
1
2
11
12
If i call showCategories("m5"); i need to get this:
17
I im currently trying to substr and find index of begin "m2" in first example and find last m index (that is m4) and remove other items from array..is there simple way?
Find the index of your marker, slice everything after it, then find the first "m" index in that array and slice up to it. All that's left is the numbers in between.
var array = ["m2", "1", "2", "11", "12", "m4", "m3", "m5", "17", "m1"];
function showCategories(marker){
let start = array.indexOf(marker);
if (start === -1) return [];
let slicedArray = array.slice(start + 1);
let end = slicedArray.findIndex(val => val.startsWith("m"));
return slicedArray.slice(0, end);
}
console.log(showCategories("m2"));
console.log(showCategories("m5"));
var array = ["m2", "1", "2", "11", "12", "m4", "m3", "m5", "17", "m1"];
function showCategories(marker) {
let currentCat = 'n';
return array.reduce((obj, item) => {
if (item.indexOf("m") === -1) {
obj[currentCat].push(item);
} else {
currentCat = item;
obj[currentCat] = [];
}
return obj;
}, {})[marker] || [];
}
console.log(showCategories("m2"));
console.log(showCategories("m5"));
Logic process
As you can see, I am using reduce and detecting if the value in the item contains an m which would indicate a new "category".
Then, I stuff all the values following the new category into an array until another category, again containing m, shows up.
Hope this helps.
Well I think you could loop through to find the index needed and store the result into a subarray.
One way would be to loop until you find the "m2" by doing:
function showCategories(find)
{
let returnArray = [];
let start = null;
if (array.includes(find) //checks if the element exists
{
for(int i = 0; i < array.length; i++)
{
if (start == null && array[i] == "m2") //looks for element
{
start = i;
}
else if(isNaN(Number(array[i]))) //pushes element into array
{
returnArray.push(array[i]);
}
else if(start != null && !isNaN(Number(array[i]))) //breaks if element after find is not an int
{
break;
}
}
}
return returnArray;
}
I haven't tested this, but something along these lines would work.
There is an object with "value" or/and "children" as properties. The problem is to add all the values and return the sum. This is working. I have used recursion. I am using a global variable to store the sum.
Please refer - https://jsfiddle.net/ws6ty78b/1/
function sumup(node) {
sum+=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sumup(node.children[i]);
}
}
return sum
}
The problem - While invoking the same function again, I am not getting same result. The sum is doubling. I DO KNOW why it is happening, that is since I am using a global variable.
Question - For the above problem, is there a way I get the same result for any number of invocations.
Please note the restrictions -
1) Do not change the function signature and declaration.
2) Use the 'sum' variable inside the 'sumup' function.
3) Do not use any extra variable.
4) Only make changes within the sumup function.
You could simply sum the values of each child to the value of the current node:
function sumup(node) {
sum=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sum+=sumup(node.children[i]);
}
}
return sum
}
You could call sumup while recursing and assign/test against a custom this:
var obj = {
"value": 4,
"children": [{
"value": 2,
"children": [{
"value": 1
}]
},
{
"value": 9
}
]
};
var sum = 0;
function sumup(node) {
//Only make change within this function body
if (!this || !this.recurse) sum = 0;
sum += node.value;
if (node.children && node.children.length > 0) {
for (var i = 0; i < node.children.length; i++) {
sumup.call({ recurse: true }, node.children[i]);
}
}
return sum
}
console.log(sumup(obj));
console.log(sumup(obj));
Alternatively, you could do away with the global variable entirely and use a recursive reduce over the children instead:
var obj = {
"value": 4,
"children": [{
"value": 2,
"children": [{
"value": 1
}]
},
{
"value": 9
}
]
};
const sumup = (node) => (
node.value + (node.children
? node.children.reduce((a, child) => a + sumup(child), 0)
: 0
)
);
console.log(sumup(obj));
console.log(sumup(obj));
In order to accomplish your goal the function sumup() will be invoked N times. We don't know how much this N is, since it depends on the number of recursions for the children nodes. Also, thanks to the restrictions, we can't edit the function signature and cannot write code elsewhere to do pretty anything, not even manually set sum to 0.
Therefore we need a way to distinguish one bunch of invocations from the NEXT bunch, and reset it.
My idea is we set a threshold, use a closure. From the first invocation, in the example, you have 5 seconds of time to keep calling and afterwards it will start anew. This is really all we can do unless another way to distinguish the invocations is provided.
EDIT: What I was trying here is keep all the recursions as a base case and not altering the object. Since OP has accepted that solution, I am adding a node resetter property. If any node has resetter not defined or null or zero or undefined, this will reset the sum. We must assume it is not defined in the started object. As I said this is kind of a weak assumption. By defining it when recursing, current sum is carried over.
I will also keep the original time threshold idea for eventual interest.
var obj = {
"value": 4,
"children": [
{
"value": 2,
"children": [
{
"value": 1
}
]
},
{
"value": 9
}
]
}
const sumup = (function(){
var lastTime = 0;
var newTime = 0;
var sum = 0;
const timeThreshold = 5000; // 5 seconds
return function(node) {
newTime = new Date().getTime();
if(!node["resetter"] || (newTime-lastTime >= timeThreshold)){
sum=0;
lastTime = newTime;
}
sum+=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sumup(Object.assign({"resetter":true},node.children[i]));
}
}
return sum;
}
})();
console.log(sumup(obj)); //16
console.log(sumup(obj)); //32! should print 16 everytime
var item = {"mtyp":2,"mtr":3,"qnt":51,"unt":"pint","nts":"cvbbcv"}
var data = [{"mtyp":"2","mtr":"2","qnt":"54","unt":"ml","nts":"ngvjn"},{"mtyp":"2","mtr":"3","qnt":"51","unt":"pint","nts":"cvbbcv"}]
output should be:
var data = [{"mtyp":"2","mtr":"2","qnt":"54","unt":"ml","nts":"ngvjn"}]
You can use below script that I have written to meet your requirement.
I am assuming that your JSON object will have similar key names at both end, if not then let me know I will update the script for you.
Your desired result will be available in resultdata.
<script type="text/javascript">
var item = { "mtyp": 2, "mtr": 3, "qnt": 51, "unt": "pint", "nts": "cvbbcv" }
var data = [{ "mtyp": "2", "mtr": "2", "qnt": "54", "unt": "ml", "nts": "ngvjn" }, { "mtyp": "2", "mtr": "3", "qnt": "51", "unt": "pint", "nts": "cvbbcv" }]
// Holds the result data.
var resultdata = [{}];
// Remove initialized result set.
resultdata.pop();
// Variable to hold comparison value.
var hasMatch = false;
// Loop through data values.
for (var index = 0; index < data.length; ++index) {
// Fetch current item.
var individualData = data[index];
// Compare item values with individual data values.
if (item.mtyp == individualData.mtyp &&
item.mtr == individualData.mtr &&
item.qnt == individualData.qnt &&
item.unt == individualData.unt &&
item.nts == individualData.nts) {
hasMatch = true;
}
else {
hasMatch = false;
}
// If then is no match then add to the result.
// ResultData will hold all the values that are not present in item.
if (!hasMatch)
{ resultdata.push(individualData); }
}
</script>
While the question is quite unclear, if you like to get a new array or an in situ (in place) solution, and despite some values does not match type wise, like
qnt: 51
and
qnt: "51"
I suggest to use a combination of Array#filter for the array itself and Object.keys with Array#every for checking all properties and get all items who not match.
var item = { mtyp: 2, mtr: 3, qnt: 51, unt: "pint", nts: "cvbbcv" },
data = [{ mtyp: "2", mtr: "2", qnt: "54", unt: "ml", nts: "ngvjn" }, { mtyp: "2", mtr: "3", qnt: "51", unt: "pint", nts: "cvbbcv" }];
data = data.filter(function (a) {
return !Object.keys(item).every(function (k) {
return a[k] == item[k];
});
});
console.log(data);
I need to reformat the following JSON data
[
{
"name": "Hello",
"value": 1
},
{
"name": "Hello",
"value": 11
},
{
"name": "Bye",
"value": 2
},
{
"name": "Bye",
"value": 22
}
]
to this:
[
{
"Hello": 1,
"Bye": 2
},
{
"Hello": 11,
"Bye": 22
},
]
There will always be an object with the same "name" field (but a different value in the "value" field) right after. I am stuck and not sure how to solve this. Is it possible to do using Lodash or pure JavaScript?
I have never before heard of Lodash, but in pure JS this can be solved with two nested loops:
function myConvert(long)
{
var short = [];
for(var i = 0; i < long.length; i++)
{
var key = long[i].name;
var value = long[i].value;
var object = null;
for(var j = 0; j < short.length; j++)
{
if(short[j][key] === undefined)
{
object = short[j];
break;
}
}
if(object === null)
{
object = {};
short.push(object);
}
object[key] = value;
}
return short;
}
This is basically:
Iterate over all elements of long.
For each of those, iterate over all elements of short to find the first element where the current name as key is not defined.
Create a new object, if not found.
Add the current value to object with name as key.
I am new to javascript & jquery, Need to remove an element from the below array structure
[{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}]
The element to be removed is known {"tag":"tag2", "description":"description2"}.
How can i find this element and remove from the array.
Please find the code which i am using to remove an element
var actionDic = [];
actionDic.push({
description: desc,
tag: tag
});
The actionDic array is populated as user enter text in textinput and selects 'add' option.
var deleterow = {
tag: "tag2",
description: "description2"
};
var index = $.inArray(deleterow, actionDic);
if (index != -1) {
actionDic.splice(index, 1);
}
The correct index is not obtained. Kindly let me know what wrong is in the code.
Thanks.
Since the comparison between the item to remove and each element in actionDic isn't trivial, you could use jQuery.grep():
actionDic = jQuery.grep(actionDic, function(elem) {
return elem.tag == deleterow.tag && elem.description == deleterow.description;
}, true);
Demo
It performs a search using a custom search function and returns the array elements that didn't match. The result replaces the previous value of actionDic and effectively removed that one item.
Update
Unfortunately, this method could be considered heavy because a new array gets created at each invocation; both in terms of what jQuery can do and standard JavaScript functionality, this particular feature is lacking. ECMAScript 6 will have the Array.prototype.find() method that will do the job of finding the index in an array (with which you can perform the splice).
You can of course write one yourself too:
(function($) {
$.find = function(arr, fn) {
for (var i = 0, len = arr.length; i < len; ++i) {
if (fn(arr[i], i, arr)) {
return i;
}
}
return -1;
};
}(jQuery));
var index = $.find(actionDic, function(elem) {
return elem.tag == deleterow.tag && elem.description == deleterow.description;
});
if (index != -1) {
actionDic.splice(index, 1);
}
Demo
I've implemented an indexOfObject method of Array prototype in one of my projects. It searches for an index of object by the given property name and value. Here it is:
Array.prototype.indexOfObject = function(searchTerm, property) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i][property] === searchTerm) {
return i;
}
}
return -1;
};
You can use this method to find the index of your object using a unique property. In your case you can use it like this:
var arr = [{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}], deleteObject = {
tag: "tag2",
description: "description2"
};
var index = arr.indexOfObject(deleteObject.tag, 'tag');
Then you can use that index to remove the object from the array:
if (index > -1) {
arr.splice(index, 1);
}
Here is the working example in JSFiddle.
var actionDic = [{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}]
var element = {"tag":"tag2", "description":"description2"}
for(var i=0;i<actionDic.length;i++) {
var found = false;
for(each in actionDic[i]) {
if(actionDic[i][each] == element[each]) {
found = true
} else {
found = false;
break;
}
}
if(found) {
actionDic.splice(i,1);
found=false;
}
}
This gets your inner array objects:
for (var x = 0; x < actionDic.length; x++){
var arrayItem = actionDic[x];
if (arrayItem["tag"] == "tag2"){
alert(arrayItem["description"]);
}
}
Working fiddle: http://jsfiddle.net/4khjp/
You can use underscore.js which contains many useful helpers for Objects, Arrays etc.
Removing array element:
array = _.reject(array, function(item) {
return item.tag == 'tag2'; // <- if tag is unique to whole array
});