Pushing new objects replaces previous object - javascript

I'm trying to push a element children text to my object reminder by passing it to to the new reminder method, but it doesn't push each of the element text it just replaces them.
$(document).on('click', '.save-reminder-button', function() {
var value = $(this).siblings('input').val(); //get the value of input
var title = $(this).siblings('h1').text(value); //set the h1
var saveSetName = $(this).parent().siblings().children('input').val();
var elem = $(this).parent().parent().children(".reminder-lists").children(); //get the reminder-lists children
$(elem).each(function(i, e) {
var txt = $(e).text(); //set txt to the elem text node
saveSetName = new ReminderSet(saveSetName)
.add(new Reminder(txt)) //create new reminder to push to reminders array
});
})
var ReminderSet = function(name) {
this.name = name;
this.reminders = [];
}
ReminderSet.prototype.add = function(reminder) {
this.reminders.push(reminder);
console.log(this.name, this.reminders);
return this;
}
ReminderSet.prototype.list = function() {
console.log(this.reminders);
}
var Reminder = function(description) {
this.description = description;
}

In your code, you create a ReminderSet object for each pushing element. Create the object once. Like this,
$(document).on('click', '.save-reminder-button', function() {
var value = $(this).siblings('input').val(); //get the value of input
var title = $(this).siblings('h1').text(value); //set the h1
var saveSetName = $(this).parent().siblings().children('input').val();
var elem = $(this).parent().parent().children(".reminder-lists").children(); //get the reminder-lists children
saveSetName = new ReminderSet(saveSetName);
$(elem).each(function(i, e) {
var txt = $(e).text(); //set txt to the elem text node
saveSetName.add(new Reminder(txt)) //create new reminder to push to reminders array
});
})

With this line:
saveSetName = new ReminderSet(saveSetName)
.add(new Reminder(txt))
You're just replacing the value of the old object with that new value, in order for it to work the way you want it you have to declare a new variable, outside the for loop:
var reminderSet = new ReminderSet(saveSetName);
And once you're inside your loop you can then add your reminders:
$(elem).each(function(i, e) {
var txt = $(e).text(); //set txt to the elem text node
reminderSet.add(new Reminder(txt))
});

Related

$ dot each not working for recursion (JS)

I have a loop in which I am calling rec_append() recursively, apparently the first pass alone works, then the loop stops.
I have an array of 4 elements going into that $.each loop but I see only the first element going into the function recursively. Help!
I switched it for a element.forEach but that gives me only the second element and I am stuck, is there a better solution to process a tree of elements? My array is a part of a tree.
var data = JSON.parse(JSON.stringify(result))
var graph = $(".entry-point");
function rec_append(requestData, parentDiv) {
var temp_parent_details;
$.each(requestData, function (index, jsonElement) {
if (typeof jsonElement === 'string') {
//Element construction
//Name and other details in the form of a : delimited string
var splitString = jsonElement.split(':');
var details = document.createElement("details");
var summary = document.createElement("summary");
summary.innerText = splitString[0];
details.append(summary);
temp_parent_details = details;
parentDiv.append(details);
var kbd = document.createElement("kbd");
kbd.innerText = splitString[1];
summary.append(' ');
summary.append(kbd);
var div = document.createElement("div");
div.className = "col";
details.append(div);
var dl = document.createElement("dl");
div.append(dl);
var dt = document.createElement("dt");
dt.className = "col-sm-1";
dt.innerText = "Path";
div.append(dt);
var dd = document.createElement("dd");
dd.className = "col-sm-11";
dd.innerText = splitString[2];
div.append(dd);
var dt2 = document.createElement("dt");
dt2.className = "col-sm-1";
dt2.innerText = "Type";
div.append(dt2);
var dd2 = document.createElement("dd");
dd2.className = "col-sm-11";
dd2.innerText = splitString[1];
div.append(dd2);
} else {
$.each(jsonElement, function (jsonElementArrIndx, jsonChildElement) {
rec_append(jsonChildElement, temp_parent_details); //Only 1 pass works, rest skip
});
}
});
}
rec_append(data, graph);
Sample data:enter image description here

Javascript stored only the last one from a loop in an JSON Object

I have a HTML Site with 4 inputRange slidern. If a user click on a button all the values from the ranges should be stored in a nested JSON Object. So far so good, but JS only saves the last one in that Array and not the others before.
But all Sliders have different values from 1 to 5, but JS saves only the 4 from the last slider. Here's my code:
//Speichert die aktuellen Angaben in einem Nested-JSON Objekt
function saveBewertung() {
var jsonObj = {};
var kriterien = [];
var bewertungen = {};
//Loop
$('input[type=range]').each(function() {
var id = $(this).attr("id");
var note = $(this).val();
bewertungen.id = id;
bewertungen.note = note;
kriterien.push(bewertungen);
jsonObj.Bewertungen = kriterien;
});
jsonObj.Kommentar = $('textarea#kommentar').val();
//TEST AUSGABE
alert(JSON.stringify(jsonObj));
}
Result:
You are pushing the same object to the array again and again. You need to initialize bewertungen every time in the each block.
Declare
var bewertungen = {};
inside the each block
$('input[type=range]').each(function() {
var bewertungen = {};
var id = $(this).attr("id");
var note = $(this).val();
bewertungen.id = id;
bewertungen.note = note;
kriterien.push(bewertungen);
});
jsonObj.Bewertungen = kriterien; //this line can be moved out
Another possibility next to the solution from #gurvinder372 is to shorten the function so you don't need to declare the variables bewertungen, id and note:
//Speichert die aktuellen Angaben in einem Nested-JSON Objekt
function saveBewertung() {
var jsonObj = {};
var kriterien = [];
//Loop
$('input[type=range]').each(function() {
// Anonymous object
kriterien.push({
id: $(this).attr("id"),
note: $(this).val()
});
});
jsonObj.Bewertungen = kriterien;
jsonObj.Kommentar = $('textarea#kommentar').val();
//TEST AUSGABE
alert(JSON.stringify(jsonObj));
}
Here is some description how this thing is working
var bewertungen = {}; // this line declare the object this object will hold values in each loop.
$('input[type=range]').each(function() {
var bewertungen = {};
var id = $(this).attr("id");
var note = $(this).val();
bewertungen.id = id; // this line add value to {bewertungen} object key
bewertungen.note = note; // this line add value to {bewertungen} object key
kriterien.push(bewertungen); // every itration will push value to [kriterien] array
});
jsonObj.Bewertungen = kriterien; // this is final array with all values

Exploit the built in XPath engine to query javaScript objects

NOTE: I am not looking for a way to query the HTML document itself. I want to create my own document from my javaScript object and pass it as root argument to the evaluate function.
Say I have the following script:
function Attribute(name, value) {
this.name;
this.value;
}
function Node(nodeName) {
this.nodeName = nodeName;
this.textContent = "";
this.childrenNodes = [];
this.attributes = [];
}
var root = new Node("root");
root.attributes.push(new Attribute("name", "treeRoot"));
var c1 = new Node("child");
c1.attributes.push(new Attribute("name", "child1"));
c1.textContent = "I'm the first child!";
var c2 = new Node("child");
c2.attributes.push(new Attribute("name", "child2"));
root.childrenNodes.push(c1);
root.childrenNodes.push(c2);
That represents the following simple XML:
<root name="treeRoot">
<child name="child1">
I'm the first child!
</child>
<child name="child2"/>
</root>
I would like to use the build in XPath engine to query this XML-like structure. Somthing like:
myDocument = createDocument(root);
myDocument.evaluate("/root/child[#name='child2']", myDocument, null, XPathResult.ANY_TYPE, null);
That would return an XPathResult of Node collection containing c1 Node.
How do I implement the createDocument function?
EDIT:
My goal is to be able to query javaScript objects. In Java I can create a Document object and use XPath to query it. I'm looking for something similar in javaScript.
You need a couple of functions here to convert your "DOM" implementation to a standard XML DOM - one to create the document and another to recursively create elements:
// create a document based on a Node instance
function toXmlDom(node) {
// create a document
var doc = document.implementation.createDocument('', '');
// convert the root node
var e = toXmlElement(doc, node);
// add root to document
doc.appendChild(e);
return doc;
}
// convert a Node and its children to an XML element
function toXmlElement(doc, node) {
// create an element
var e = doc.createElement(node.nodeName);
// set its attributes
for(var i = 0; i < node.attributes.length; i++) {
var attr = node.attributes[i];
e.setAttribute(attr.name, attr.value);
}
// set its text content
e.textContent = node.textContent;
// convert and add its child nodes
for(var i = 0; i < node.childrenNodes.length; i++) {
var childrenNode = node.childrenNodes[i];
var childNode = toXmlElement(doc, childrenNode);
e.appendChild(childNode);
}
return e;
}
// do the conversion
var myDocument = toXmlDom(root);
Working Example
console.clear();
function Attribute(name, value) {
this.name = name;
this.value = value;
}
function Node(nodeName) {
this.nodeName = nodeName;
this.textContent = "";
this.childrenNodes = [];
this.attributes = [];
}
function toXmlDom(node) {
// create a document
var doc = document.implementation.createDocument('', '');
// convert the root node
var e = toXmlElement(doc, node);
// add root to document
doc.appendChild(e);
return doc;
}
function toXmlElement(doc, node) {
// create an element
var e = doc.createElement(node.nodeName);
// set its attributes
for(var i = 0; i < node.attributes.length; i++) {
var attr = node.attributes[i];
e.setAttribute(attr.name, attr.value);
}
// set its text content
e.textContent = node.textContent;
// convert and add its child nodes
for(var i = 0; i < node.childrenNodes.length; i++) {
var childrenNode = node.childrenNodes[i];
var childNode = toXmlElement(doc, childrenNode);
e.appendChild(childNode);
}
return e;
}
var root = new Node("root");
root.attributes.push(new Attribute("name", "treeRoot"));
var c1 = new Node("child");
c1.attributes.push(new Attribute("name", "child1"));
c1.textContent = "I'm the first child!";
var c2 = new Node("child");
c2.attributes.push(new Attribute("name", "child2"));
root.childrenNodes.push(c1);
root.childrenNodes.push(c2);
var myDocument = toXmlDom(root);
// get the text of the first child - "I'm the first child!"
var result = myDocument.evaluate("/root/child[#name='child1']", myDocument, null, XPathResult.ANY_TYPE, null);
var thisNode = result.iterateNext();
while (thisNode) {
document.getElementById('result').innerHTML += thisNode.textContent + "<br/>";
thisNode = result.iterateNext();
}
document.getElementById('doctext').value = myDocument.documentElement.outerHTML;
<p><b>/root/child[#name='child1'].textContent:</b> <span id="result"></span></p>
<b>Document XML</b><br/>
<textarea id="doctext" cols="50" rows="10"></textarea>

How do I iterate over an IndexedDB objectStore using a condition on a non-key property?

I have a select box that I want to populate automatically with values from a objectStore, for that I need to iterate it like this: "Select COL1 from TABLE where COL2 = 'myvalue'",
this is my code:
var db;
var req = indexedDB.open("DB");
req.onsuccess = function (e) {
db = req.result;
var tran = db.transaction("store");
var singleKeyRange = IDBKeyRange.only("myvalue"); //the value I want to reach from COL2
tran.objectStore("store").openCursor(singleKeyRange).onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
var opt = document.getElementById("selectbox");
var option = document.createElement("option");
var optionText=document.createTextNode(cursor.value.COL1); //the matching values in COL1
option.appendChild(optionText);
opt.appendChild(option);
cursor.continue();
}
}
};
I have all my values correctly indexed in the objectStore, just don't now how to reach values through others values.
Here is an example in which items are searched on non-indexed column, you need to go through all items and compare the values and add them to list, after that you can return the result set.
function SearchItems( keyPath, value, requestNo, callback){
var initOpenReq = indexedDB.open(baseName);
initOpenReq.onsuccess = function() {
var db = initOpenReq.result;
var transaction = db.transaction(objectStoreName, 'readonly');
var objectStore = transaction.objectStore(objectStoreName);
var cursorRequest = objectStore.openCursor();
var agregate = [];
cursorRequest.onsuccess = function (event){
if (event.target.result){
if(event.target.result.value[keyPath] && event.target.result.value[keyPath] == value){ //compare values
agregate.push(event.target.result.value);
}
event.target.result['continue']();
}
};
transaction.oncomplete = function (event) {
callback(agregate); // return items
};
}
}
This is an example with an index.
var db;
var req = indexedDB.open("DB", 2);
// Creating the index
req.onupgradeneeded = function (e){
var trans = e.target.transaction;
var obj = trans.objectStore("store");
obj.createIndex("indexname", "keypath") // keypath is the propertyname you want the index on. for Ex. {Name: "x", Age:5 }; If you want to filter on Name, keypath = Name
}
req.onsuccess = function (e) {
db = req.result;
var tran = db.transaction("store");
var singleKeyRange = IDBKeyRange.only("myvalue"); //the value I want to reach from COL2
var objectStore = tran.objectStore("store");
var opt = document.getElementById("selectbox");
objectStore.index("indexname").openCursor(singleKeyRange).onsuccess =
function(e){
var cursor = e.target.result;
if (cursor) {
var option = document.createElement("option");
var optionText=document.createTextNode(cursor.value.COL1); //the matching values in COL1
option.appendChild(optionText);
opt.appendChild(option);
cursor.continue();
}
}
};

Sorting the results of an indexedDB query

I want to sort results obtained from indexedDB.
Each record has structure {id, text, date} where 'id' is the keyPath.
I want to sort the results by date.
My current code is as below:
var trans = db.transaction(['msgs'], IDBTransaction.READ);
var store = trans.objectStore('msgs');
// Get everything in the store;
var keyRange = IDBKeyRange.lowerBound("");
var cursorRequest = store.openCursor(keyRange);
cursorRequest.onsuccess = function(e) {
var result = e.target.result;
if(!!result == false){
return;
}
console.log(result.value);
result.continue();
};
Actually you have to index the date field in the msgs objectStore and open an index cursor on the objectStore.
var cursorRequest = store.index('date').openCursor(null, 'next'); // or prev
This will get the sorted result. That is how indexes are supposed to be used.
Here's the more efficient way suggested by Josh.
Supposing you created an index on "date":
// Use the literal "readonly" instead of IDBTransaction.READ, which is deprecated:
var trans = db.transaction(['msgs'], "readonly");
var store = trans.objectStore('msgs');
var index = store.index('date');
// Get everything in the store:
var cursorRequest = index.openCursor();
// It's the same as:
// var cursorRequest = index.openCursor(null, "next");
// Or, if you want a "descendent ordering":
// var cursorRequest = index.openCursor(null, "prev");
// Note that there's no need to define a key range if you want all the objects
var res = new Array();
cursorRequest.onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
res.push(cursor.value);
cursor.continue();
}
else {
//print res etc....
}
};
More on cursor direction here: http://www.w3.org/TR/IndexedDB/#cursor-concept
IDBIndex API is here: http://www.w3.org/TR/IndexedDB/#idl-def-IDBIndex
Thanks to zomg, hughfdjackson of javascript irc, I sorted the final array. Modified code as below:
var trans = db.transaction(['msgs'], IDBTransaction.READ);
var store = trans.objectStore('msgs');
// Get everything in the store;
var keyRange = IDBKeyRange.lowerBound("");
var cursorRequest = store.openCursor(keyRange);
var res = new Array();
cursorRequest.onsuccess = function(e) {
var result = e.target.result;
if(!!result == false){
**res.sort(function(a,b){return Number(a.date) - Number(b.date);});**
//print res etc....
return;
}
res.push(result.value);
result.continue();
};

Categories