Fill javascript object with form data - javascript

I have an object declared, and I have an html form with some matching fields.
All fields in the form are in the object, but the object also has a couple of additional variables and functions.
I'd like to fill the object with the data entered in the form, what I'm trying right now overwrites the declared object, and so doesn't have the functions nor the other variables.
The object :
var Container = {
nodes: [],
Contains: function (Node) {
for (var i = 0; i < this.nodes.length; i++) {
if (this.nodes[i].nodeID === Node.nodeID)
return (i);
}
return (-1);
}
How I fill it from the form :
const handleContainerForm = event => {
event.preventDefault();
ContainerFormToJSON(form.elements);
var i = JSONData.Contains(Container);
if (i === -1)
JSONData.containers.push(Container);
else
JSONData.container[i] = Container;
output = JSON.stringify(JSONData, null, " ");
displayContents(output);
};
The form has ID, Title, Folder, Image and Description as fields, so this last Container object doesn't have the Contains() function nor the nodes[] array.
How do I end up with a complete, filled version of the object I have declared ?

In ContainerFormToJSON function, before the statement
return Container
define:
//container.nodes and container.contains

You are right, JavaScript is very different from C#, especially in regards to OOP. But that doesn't make it better or worse.
In JavaScript, you don't need to declare an object's properties, like you have to when you use classes. I think that you only want to serialize the form's input values to JSON. I recommend not to use an object that additionally has a nodes property and a Contains method.
If you need to keep a copy of the unserialized object, create two objects:
class Container {
constructor () {
this.nodes = [];
}
indexOf (node) {
return this.nodes.findIndex(n => n.nodeID === node.nodeID);
}
}
Container.nodeID = 0; // think of it as a static property
function extractValues (elements) {
// 'elements' is an array of <input> elements
// the 'container' will be filled and serialized
var container = new Container();
for (var index in elements) {
var element = elements[index];
container[element.name] = element.value;
}
container.nodeID = Container.nodeID++; // give the container a unique ID
return container;
}
var inputs = document.querySelectorAll('input');
var jsonData = new Container();
document.querySelector('button').addEventListener('click', function () {
var newContainer = extractValues(inputs);
var index = jsonData.indexOf(newContainer);
if (index === -1) {
jsonData.nodes.push(newContainer);
} else {
jsonData.nodes[index] = newContainer;
}
var jsonString = JSON.stringify(jsonData, null, ' ');
console.log(jsonString);
});
<input name="containerID">
<input name="containerTitle">
<!-- ... -->
<button>Serialize</button>
Please note: only setting an object's properties doesn't make it to JSON. It's only JSON if it's serialized to a string. I recommend this article. To serialize a JavaScript object, use JSON.stringify.
Edit:
Looking at the edit of your question, I think it might be preferable to create a Container class. Both jsonData and the containers of the form data will be instances of that class. It can contain other containers (nodes), and can get the index of such a nested container using the indexOf method. I implemented this in the above code snippet. Whenever you hit the "Serialize" button, a new container with the current <input>s' contents will be added to jsonData. The JSON form of jsonData will be logged to the console.
I hope this is what you are looking for. To better understand JavaScript OOP,
take a look at some of the articles at MDN.

Related

How to retrieve a specific object from a JSON value stored in sessionStorage?

I have this stored in the session:
What I'm looking to do is assign each object in the JSON as a variable so I can add them to the DOM appropriately.
This works but prints everything out:
if (sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9') != null) {
$(sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9')).appendTo('.div');
}
What I'd like is something like this, but it doesn't work:
var div1 = $(JSON.parse(sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9', 'a.cart-contents')));
var div2 = $(JSON.parse(sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9', 'a.footer-cart-contents')));
var div3 = $(JSON.parse(sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9', 'div.widget_shopping_cart_content')));
Any help would be greatly appreciated. Thank you!
Getting the same value from the storage several times is not a good idea. In addition, you need better names for your variables.
var json = sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9');
if (json) {
var data = JSON.parse(json);
if (data) {
var cart_link = $(data['a.cart-contents']),
footer_link = $(data['a.footer-cart-contents']),
widget_div = $(data['div.widget_shopping_cart_content']);
}
}
So it appears you have set selectors as keys of the object so you could iterate those keys to get each selector.
The propose of those selector keys is not 100% clear. I am assuming that those selectors are the elements you want to insert the html strings into and that $() means you are using jQuery
if (sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9') != null) {
var data = JSON.parse(sessionStorage.getItem('wc_fragments_aaf6a2e5b971cb51d59e8f3eae9b34c9');
$.each(data, function(selector, htmlString){
$(selector).append(htmlString)
});
}

How to reference variable from scope in AngularJS

Version: 1.5.5
I have two arrays in my scope, let's call them:
$scope.array1 = [1,2,3,4];
$scope.array2 = [5,6,7,8];
I want to modify one of this arrays based on a condition, for this I want to use the ternary conditional because I'll make changes on the array in different parts of my code, thus I'll avoid repeating the condition multiple times:
var header = (myCondition)?$scope.array1:$scope.array2;
header = [];
header.push(10);
//some code
header.push(11);
But this is not working! The changes on header are not reflected on the object in the $scope.
So I have to do this:
if(myCondition){
$scope.array1 = [];
$scope.array1.push(10);
}
else{
$scope.array2 = [];
$scope.array2.push(10);
}
//some code
if(myCondition){
$scope.array1.push(11);
}
else{
$scope.array2.push(11);
}
Which seems awful...
I think the first way should really work because header will keep the reference to the object in the $scope. Anyway, that was the dummy code to make my point, here is the real code (sorry if it's awful. My first time with Javascript):
$scope.getHeaders = function(type){
req = createJsonedFilters(false, true, true);
req['type'] = type;
$http.post("/getHeaders", req).then(
function(res){
data = res.data;
if(data['msg'] == "OK"){
var minmax = (type == 'epidem')?"epidemMinMax":"entomoMinMax";
var headers = (type == 'epidem')?$scope.epidemHeaders:$scope.entomoHeaders;
headers = [];
data_minmax = data[minmax]
minmax_headers = Object.keys(data_minmax).sort();
console.log(minmax_headers);
for(var i=0; i < minmax_headers.length; i++){
var minmax_name = minmax_headers[i];
var mm_elem = data_minmax[minmax_name]
var atributo = {
name: minmax_name,
enabled: true,
slider: {minValue: parseInt(mm_elem['min']), maxValue: parseInt(mm_elem['max']),
options: {floor: parseInt(mm_elem['min']),ceil: parseInt(mm_elem['max']),
step: 1}}
};
headers.push(atributo);
}
console.log(headers);
$scope.refreshAttributes();
}
else{
console.log('Empty ' + type + ' Dataset...')
}
},
function(){
console.log("Couldn't load " + type + " headers...")
}
);
}
Any ideas why the reference to headers won't modify the object in the scope? If there is any output I can give you, comment and I'll update the question.
The arrays are properties of the $scope object. You can thus access them using their key with the syntax $scope[arrayName] (where arrayName is a string).
Therefore, using myCondition, you have to store the name of the array you want to modify in a variable that you'll use in the following steps.
var arrayName = (myCondition) ? 'array1' : 'array2';
$scope[arrayName] = [];
$scope[arrayName].push(10);
//some code
$scope[arrayName].push(11);
EDIT
Your code doesn't work because you erase the reference to the $scope.array1 by creating a new array (header = []).
You could copy the content of the header array into the appropriate array of your $scope after all the operations are made.
var header = [];
header.push(10);
//some code
header.push(11);
if (myCondition) {
$scope.array1 = header;
} else {
$scope.array2 = header;
}
The reason why is was not working with the reference for headers is when you assign appropriate array via
var headers = (type == 'epidem')?$scope.epidemHeaders:$scope.entomoHeaders;
Now the headers will hold the reference for either of the $scope.epidemHeaders or $scope.entomoHeaders array(as array is also an object).
And when you try to assign the new array to headers via headers = []. The headers now holds new reference, not either of the $scope.epidemHeaders or $scope.entomoHeaders array. i.e headers will be pointing to different array, whereas say $scope.epidemHeaders = [1,2,3,4] and $scope.entomoHeaders = [5,6,7,8]
Hence pushing to headers after assigning new array wont push the element to the array on the $scope. In fact it adds to the new array. Hence the changes weren't reflected.
If you still want to use the header ways of reference, try pushing the element without setting the new array.
Or if resetting is your case then use the below mentioned way:
var headers = (type == 'epidem')?$scope.epidemHeaders:$scope.entomoHeaders;
headers.length = 0; // Trick to reset the array retaining the same reference
headers.push(11);

Iterating over and comparing properties of two arrays of objects

I have set up a HBS helper which takes in two arrays of objects (users privileges). What I want to do is compare them and inject back into the template the privileges the user does and doesn't have.
Presently I can compare the names of the privileges with the following code:
hbs.registerHelper('selected', function(option, value){
var i;
var j;
var privName;
var userPriv;
var privObj = new Object();
var privArray = [];
for(i in option){
console.log('each ' + JSON.stringify(option[i]));
privName = option[i].privname;
for (y in value){
if(privName == value[y].privname){
userPriv = value[y].privname;
console.log('user has the following privileges', value[y].privname);
privObj = new Object();
privObj.name = userpriv;
privObj.id = value[y]._id;
privObj.state = 'selected';
privArray.push(privObj);
} else if (privName != value[y].privname){
console.log('user doesnt have priv ', privName);
privObj = new Object();
privObj.name = option[i].privname;
privObj.id = option[i].id;
privObj.state = '';
privArray.push(privObj);
}
}
}
console.log('privileges array ', privArray);
return privArray;
});
This works OK when the user only has one privilege, however when the user has more than one, for example two privileges, it returns the privileges twice. If the user has 3, thrice and so on. I know this is because the array is looping again because their are 2, 3 etc in the .length. However I can't seem to find an adequate solution.
Any help?
P.S. it would be nice if the Array.includes() method allowed you to search object properties.
The problem creating new objects the way you did is that for each property you add to your privilege-entity you will have to return to that function and set that property as well. You can instead just add/alter the state property of the existing objects:
hbs.registerHelper('selected', function(option, value) {
var names = option.map(function(opt) {
return opt.privname;
});
value.forEach(function(val) {
val.state = names.indexOf(val.privname) >= 0 ? 'selected' : '';
});
return value;
});
Basically:
The variable names is being mapped to be an array only with the privnames. You can check by using console.log(names).
The Array.forEach() function is helpful in this case because you just need to iterate over each object inside value and set its state-property.
To check if the privname exists, you just need to check the index in the previous names-mapped-array. For such a simple thing I used ternary operator (?:).
Finally, you return value, which is the array containing the objects you had updated.

Numerically ordered ID's of data objects in Firebase

I am pretty new to the 'game' and was wondering if it's possible to order newly added data (through a form and inputs) to the Firebase numerically so each new data entry gets the ID (number of the last added data +1).
To make it more clear, underneath you can find a screenshot of how data is currently being added right now. The datapoint 0-7 are existing (JSON imported data) and the ones with the randomly created ID belong to new entries. I would like to have the entries to comply to the numbering inside of my Firebase, because otherwise my D3 bar chart won't be visualised.
var firebaseData = new Firebase("https://assignment5.firebaseio.com");
function funct1(evt)
{
var gameName = $('#nameInput').val();
var medalCount = $('#medalsInput').val();
var bool = $('#boolInput').is(':checked');
firebaseData.push().set({games: gameName, medals: medalCount, summergames: bool});
evt.preventDefault();
}
var submit = document.getElementsByTagName('button')[0];
submit.onclick = funct1;
UPDATE:
function funct1(evt)
{
var gameName = $('#nameInput').val();
var medalCount = $('#medalsInput').val();
var bool = $('#boolInput').is(':checked');
for (var i = 0; i < 10; i++)
{
firebaseData.child('7' + i).set({games: gameName, medals: medalCount, summergames: bool}(i)); };
Problem:
There are two ways to generate ids for your document nodes.
Calling .push() on your reference will generate that unique id.
Calling .set() on your reference will allow you to use your own
id.
Right now you're using .push().set({}), so push will generate an new id and the set will simply set the data.
// These two methods are equivalent
listRef.push().set({user_id: 'wilma', text: 'Hello'});
listRef.push({user_id: 'wilma', text: 'Hello'});
Using .set() without .push() will allow you to control your own id.
Using .push():
When managing lists of data in Firebase, it's important to use unique generated IDs since the data is updating in real time. If integer ids are being used data can be easily overwritten.
Just because you have an unique id, doesn't mean you can't query through your data by your ids. You can loop through a parent reference and get all of the child references as well.
var listRef = new Firebase('https://YOUR-FIREBASE.firebaseio.com/items');
// constructor for item
function Item(id) {
this.id = id;
};
// add the items to firebase
for (var i = 0; i < 10; i++) {
listRef.push(new Item(i));
};
// This will generate the following structure
// - items
// - LGAJlkejagae
// - id: 0
// now we can loop through all of the items
listRef.once('value', function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var name = childSnapshot.name();
var childData = childSnapshot.val();
console.log(name); // unique id
console.log(childData); // actual data
console.log(childData.id); // this is the id you're looking for
});
});
Within the childData variable you can access your data such as the id you want.
Using .set()
If you want to manage your own ids you can use set, but you need to change the child reference as you add items.
for (var i = 0; i < 10; i++) {
// Now this will create an item with the id number
// ex: https://YOUR-FIREBASE.firebaseio.com/items/1
listRef.child('/' + i).set(new Item(i));
};
// The above loop with create the following structure.
// - items
// - 0
// - id: 0
To get the data you can use the same method above to loop through all of the child items in the node.
So which one to use?
Use .push() when you don't want your data to be easily overwritten.
Use .set() when your id is really, really important to you and you don't care about your data being easily overwritten.
EDIT
The problem you're having is that you need to know the total amount of items in the list. This feature is not implemented in Firebase so you'll need to load the data and grab the number of items. I'd recommend doing this when the page loads and caching that count if you really desire to maintain that id structure. This will cause performance issues.
However, if you know what you need to index off of, or don't care to overwrite your index I wouldn't load the data from firebase.
In your case your code would look something like this:
// this variable will store all your data, try to not put it in global scope
var firebaseData = new Firebase('your-firebase-url/data');
var allData = null;
// if you don't need to load the data then just use this variable to increment
var allDataCount = 0;
// be wary since this is an async call, it may not be available for your
// function below. Look into using a deferred instead.
firebaseData.once('value', function(snapshot) {
allData = snapshot.val();
allDataCount = snapshot.numChildren(); // this is the index to increment off of
});
// assuming this is some click event that adds the data it should
function funct1(evt) {
var gameName = $('#nameInput').val();
var medalCount = $('#medalsInput').val();
var bool = $('#boolInput').is(':checked');
firebaseData.child('/' + allDataCount).set({
games: gameName,
medals: medalCount,
summergames: bool
});
allDataCount += 1; // increment since we still don't have the reference
};
For more information about managing lists in Firebase, there's a good article in the Firebase API Docs. https://www.firebase.com/docs/managing-lists.html

Javascript and HTML data model and presentation model design question

so I've been working on a project in Javascript that takes in objects the user provides and represents them in HTML. Right now they are represented in memory as an array, and in the display as a separate array. After integrating some code changes, problems have arisen in that the display array seems to be having troubles removing it's contents, thus things that should be removed don't disappear from the view.
Declaring lists:
this.divList = gDocument.getElementById( element );
this.objectList = [];
Adding an object to the lists:
addObject = function (address, type){
var newDiv = gDocument.createElement("div");
this.divList.appendChild( newDiv );
var d = this.createObject( newDiv, address, type );
if (undefined != d)
{
this.objectList.push(d);
}
}
The divList accurately reflects the objectList until any changes are made to the objectList at runtime. When restarted, the lists are in sync once again. When I tried to fix it, things were very complicated. I'm wondering if there is a better way to design such an idea (the object model and the graphical representation). Any comments would be helpful, thanks.
Question vagueness aside, my recommendation would be to store one list, not two, in memory. Each list element is an object with all the necessary data you need for that particular abstract "object" (the ones that "the user provides"). Something like this:
this.divList = gDocument.getElementById(element);
this.masterList = [];
var i,
len = this.divList.length;
for (i = 0; i<len; i++)
{
this.masterList.push({
elt: this.divList[i],
obj: /* however you'd create the object in this.objectList */
});
}
Edit: your addObject function would be changed to something like this:
addObject = function (address, type)
{
var newDiv = gDocument.createElement("div"),
newObj = {elt: newDiv,
obj: this.createObject(newDiv, address, type)};
this.masterList.push(newObj);
this.divList.appendChild(newDiv);
}
You should store a reference to the HTML element that you're appendChild()ing to. You're already doing this - but when you need to manipulate the individual elements (say, remove one), use the masterList instead:
removeObject = function (i)
{
var toRemove = this.masterList.splice(i, 1);
if (toRemove)
{
this.divList.removeChild(toRemove.elt);
}
}
See also Array.splice().

Categories

Resources