i'm tryink to push an object inside a json object, but it gives me a duplicated json object, i will expalin:
heres my html:
<input type="text" style="width: 40% !important;" placeholder="Nom" class="input-sm" ng-model="company.link.nom" />
<input type="text" style="width: 40% !important;" placeholder="Lien" class="input-sm" ng-model="company.link.value" />
<a class="btn btn-wide btn-primary" ng-click="company.addExternalLinktoGrid()"><i class="fa fa-plus"></i> Ajouter </a>
here is addExternalLinktoGrid function:
var linkJsonObj = [];
var cp=1;
company.addExternalLinktoGrid = function() {
company.link.id=cp;
currentObj.push(company.link);
console.log(JSON.stringify(company.link));
linkJsonObj.push(company.link);
console.log(JSON.stringify(linkJsonObj));
cp++;
}
For example, lets assume we add new object: company.link.nom="toto" and company.link.value="titi", in this case linkJsonObj print:
[{"nom":"toto","value":"titi","id":1}]
lets add the second object company.link.nom="momo" and company.link.value="mimi", in this case linkJsonObj print:
[{"nom":"momo","value":"mimi","id":2},
{"nom":"momo","value":"mimi","id":2}]
This is what I got, I don't know why? but the expected behaviour is:
[{"nom":"toto","value":"titi","id":1},
{"nom":"momo","value":"mimi","id":2}]
can anyone help please?
company.link in an object and if you push this object to an array it is passed by reference. If you overwrite the values of this object it will be overwritten in your array. What you need is to copy the object (values). If you push it multiple times to an array the array will contain multiple references to the same object.
var newObject = {
nom: company.link.nom,
value: company.link.value,
id: cp
}
linkJsonObj.push(newObject);
Related
I'm building a To Do list app and have a question regarding OOP and JavaScript. I want to create a value in the Constructor that holds my taskBody which contains the HTML and template literal that will be assigned by either the input value or an eventual population from local storage. My goal is to re-use this HTML in two separate functions, but I'm stuck with the template literal.
class Task {
constructor() {
let taskValue //Initializing a variable
this.taskBody = `<div class="task">
<span>${taskValue}</span> //Template Literal
<span class="actions">
<a class="edit-button" title="Edit Task">Edit</a>
<button class="complete-button" title="Complete Task"><i class="fas fa-check"></i></button>
</span>
</div>`;
}
addTask = () => {
//Prevent empty task
if (this.input.value == "") {
this.setPlaceholder("Please Enter A Task");
return;
}
this.taskValue = this.input.value; //Trying to reassign taskValue to the input value
this.results.innerHTML += this.taskBody; //Trying to grab the HTML from the constructor and populate with taskValue able
ls.setLS(this.taskValue); //setting the Local Storage the Task Value, which works
};
}
I expect if I type "Stack Overflow" in the to-do list, "Stack Overflow" populates in the HTML and the Local Storage, however, it only populates in the Local Storage. The todo item is either undefined, null, or empty.
I've tried using this.taskValue, let taskValue = "", and let taskValue = null, but I get the results described above. Where am I going wrong, and more specifically, how can I reuse the HTML in different functions?
Here's a CodePen where you can see the issue:
Codepen
When you first instantiate the Task, the value of the this.taskBody is set as below:
<div class="task">
<span>undefined</span>
<span class="actions">
<a class="edit-button" title="Edit Task">Edit</a>
<button class="complete-button" title="Complete Task"><i class="fas fa-check"></i></button>
</span>
</div>
with undefined value, because at the moment of instantiation, the taskValue is undefined.
If your todo list items are added dynamically (which is the case), consider having a function which will enable dynamic replacement, like:
getTaskBody = item => `<div class="task">
<span>${item}</span>
<span class="actions">
<a class="edit-button" title="Edit Task">Edit</a>
<button class="complete-button" title="Complete Task"><i class="fas fa-check"></i></button>
</span>
</div>`;
and use it later in line 123, instead of:
this.results.innerHTML += this.taskBody;
do:
this.results.innerHTML += getTaskBody(this.taskValue);
I have an obeservable array in Knockout, say data that contains objects with observable properties. In one part of my application I want to allow users to add to this array and ultimately mess about with it, but if they cancel to revert the array to the original state.
One solution I though of is to create a copy called dataCopy that replaces the original array in the event of cancellation, but this only creates another pointer to the same underlying data, so it will also reflect the changes that were made which is not what I want.
I've tried converting it to javascript, via ko.toJS(data) and this creates a js array of the data, however all of the objects lose their observable properties and when I re-create the data using ko.observableArray(dataCopy) the app falls over as the properties of the objects are no longer observable.
How can I create a clone of a knockout array rather than another pointer?
This is an example of how you could achieve this using the ko mapping plugin for deeply copying your observable arrays.
I doubt any other method of copying would work for you such as .slice or ko.toJS since as you mentioned you want a deep copy which goes as far as the underlying object's observable propertieš.
The important part here is the function :
function obsArrDeepCopy(from, to) {
ko.mapping.fromJS(ko.toJS(from), {}, to);
}
Which will do the deep copy by first converting the source array to a plan JS array and then populate the target array converting to observables the underlying object properties.
Full working example:
function Person(name) {
this.name = ko.observable(name);
}
var viewModel = {
people: ko.observableArray([
new Person("Annabelle"),
new Person("Bertie"),
new Person("Charles")
]),
peopleCopy: ko.observableArray(),
newName: ko.observable(''),
addPerson: function() { this.peopleCopy.push(new Person(this.newName())) },
commit: function() { obsArrDeepCopy(this.peopleCopy, this.people) },
cancel: function() { obsArrDeepCopy(this.people, this.peopleCopy) },
};
ko.applyBindings(viewModel);
obsArrDeepCopy(viewModel.people, viewModel.peopleCopy);
function obsArrDeepCopy(from, to) {
ko.mapping.fromJS(ko.toJS(from), {}, to);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<h2> Initial </h2>
<ul data-bind="foreach: people">
<li>
<span data-bind="text: name" />
</li>
</ul>
<br/><br/>
<h2> Copy </h2>
<ul data-bind="foreach: peopleCopy">
<li>
<span data-bind="text: name" />
</li>
</ul>
<input type="text" data-bind="textInput: newName" />
<button type="button" data-bind="click: addPerson"> Add </button>
<br/><br/>
<button type="button" data-bind="click: commit"> Commit </button>
<button type="button" data-bind="click: cancel"> Cancel </button>
Inspired from this codepen I used a JSON file to load some basic input fields and toggles. When the user change something and press save, I would like to save these new property values in a new JSON object with same property names.
My code looks the this
JS
.controller('page', function($scope, templateSettingsFactory, savedSettingsFactory) {
$scope.template = templateSettingsFactory;
$scope.saved = savedSettingsFactory;
$scope.saveSettings = function(){
var temp = $scope.template;
var jsonObj = {};
for(var key in temp){
jsonObj[key]=temp[key];
}
$scope.saved.$add(jsonObj);
};
});
HTML
<label ng-repeat="item in template">
<input type="text" placeholder="{{item}}">
</label>
<button class="button" ng-click="saveSettings()">Save</button>
The problem is that calling the saveSettings() don't get the updated property values of $scope.template - perhaps it's not doing two-way binding?
You need to use ng-model on your form elements to bind their input to the scope.
<input type="text" ng-model="item.property">
Here is an example of binding to a single object with arbitrary keys:
<div ng-repeat="(key,value) in template">
<div>{{key}}</div>
<input type="text" ng-model="template[key]"/>
</div>
https://docs.angularjs.org/api/ng/directive/ngModel
<div class="form-group" data-ng-repeat="choice in choices">
<input type="text" ng-model="user.subjectname[$index]"
name="subject" ng-required="true" placeholder="Enter a subject name">
</div>
As I am creating this input field dynamically using ng-repeat, if I used ng-model=user.subjectname, the input text for some reason was same in all the fields, I searched over the internet and found ng-model="user.subjectname[$index]" being used and it worked.
However, i am not able to understand
what it exactly means. ?
2.If it's array or an object. ?
It shows up as object in console. ?
If it's object, why does it have an index?
Also, as we can iterate over object vals using this format:
ng-repeat="(key,val) in user.subjectname"{{val}}
Why did it not work?
neither did ng-repeat="subject in user.subjectname"{{subject}}
Can I please get directions as I am very confused about it at the moment.
It is an array. When you do :
var test = []; console.info(typeof test);// You would get object as arraysa re also object in Javascript.
Here you are passing $index of choice in choices to subjectname array. Which is fine. After populating subjectname with some of the data, you can use ng-repeat like
ng-repeat = "subject in user.subjectname"
Also initialize user.subjectname = []; in controller
<form class="idea item">
<div ng-repeat="(key, value) in items[0]" >
<label>{{key}}</label>
<input type="range" ng-model="items[0][key]" min="0" max="15"/>
</div>
<input type="submit" ng-click="save()" />
<pre>{{items | json}}</pre>
var app = angular.module('my-app', [], function () {
})
app.controller('AppController', function ($scope) {
$scope.items = [{"red": 14, "green": 12, "orange": 1, "yellow": 11, "blue": 9}];
})
I'm building an app using AngularJS and LocalStorage. I've run into a problem that it's a tad too complex for me.
I have a list of people, and the idea is to be able to add arrays of names. I choose X names, click add, creates an object in an array, it resets the list, and I can start over, choose X names, click add, etc.
Here's how I create the temporary array that then I push into LocalStorage:
HTML:
<form>
<div class="col-md-3" ng-repeat="staff in stafflist | orderBy: 'name'">
<button class="btn form-control" ng-show="!staff.chosen" ng-click="pushStaff(staff)">{{staff.name}}</button>
<button class="btn btn-primary form-control" ng-show="staff.chosen" ng-click="unpushStaff(staff)">{{staff.name}}</button>
</div>
<button class="btn ng-click="addRecord()">Add passangers</button>
</form>
JS:
$scope.paxlist = [];
$scope.pushStaff = function (staff) {
staff.chosen = true;
$scope.paxlist.push(staff);
console.log($scope.paxlist);
};
$scope.unpushStaff = function (staff) {
staff.chosen = false;
var index=$scope.paxlist.indexOf(staff)
$scope.paxlist.splice(index,1);
console.log($scope.paxlist);
}
My problem is that I can create objects into the array, but when I add an object, the selected items of the list of names won't reset, so they will be pre-selected when adding the next object.
At the same time, it will also stay linked to the last object added, so when I modify the selection, the last object will also get modified.
This also messes with the possibility of adding an editing capability for each object of the array.
I've created a Plnkr that illustrates the issue.
If you could shed some light on the issue, that would be brilliant.
In addRecord you need reset property chosen
$scope.addRecord = function () {
$scope.recordlist.push({ pax: angular.copy($scope.paxlist) });
jsonToRecordLocalStorage($scope.recordlist);
$scope.editItem = false;
$scope.paxlist = [];
$scope.stafflist.forEach(function (el) {
el.chosen = false;
});
};
Demo: http://plnkr.co/edit/vV8OuKiTKYkFyy7SrjOS?p=preview