AngularJS - How do I push key value pairs into an array? - javascript

I'm attempting to push a new object with some key:value pairs into an array using AngularJS, and seem to be running into some trouble.
Here's the html:
<div class="small-12 medium-6 large-6 columns">
<div id="addSubTarget">
<p>Add Targets</p>
<input type="text" ng-model="sublevel.tagName">
<button type="button" class="resultsButton" ng-click="addTag()">Submit</button>
</div>
<div id="addSubTargetBox">
<p>Targets Added</p>
<div id="targetAddedBox">
<div class="targetAddedInBox" ng-repeat="tag in tagsFeed track by $index">
{{tag}}
<i class="fa fa-trash-o" title="Delete this tag" ng-click="deleteTag($index)"></i>
</div>
</div>
</div>
</div>
<div class="small-12 medium-6 large-6 columns">
<div class="sublevelAddTextArea">
<p>Instructions</p>
<textarea rows="4" ng-model="sublevel.instructions"></textarea>
</div>
<div class="sublevelAddTextArea">
<p>Response</p>
<textarea rows="4" ng-model="sublevel.response"></textarea>
</div>
</div>
And the button here:
<button type="button" class="resultsButton" ng-click="submitNewSub()">Submit</button>
Here's the function in the controller:
$scope.submitNewSub = function(){
var arrayForUse = [];
arrayForUse.push({
tag: $scope.tagsFeed,
instructions: $scope.sublevel.instructions,
response:$scope.sublevel.response
});
console.log(arrayForUse);
$scope.listTable.push(arrayForUse);
}
I am using a hard coded array for testing it looks like this:
$scope.listTable = [{
tag: "tags 1",
instructions: "instructions 1",
response: "response 1"
},
{
tag: "tags 2",
instructions: "instructions 2",
response: "response 2"
}];
I basically need those inputs to push onto that array in that structure so angular two-way data binding will update my front end, however something seems to not be working for me.

I think you want to push each element from the arrayForUse array one by one, not the whole array at once. Therefore you will want to change $scope.listTable.push(arrayForUse) by:
Array.prototype.push.apply($scope.listTable, arrayForUse);
Which takes each element in arrayForUse and pass it to the push method as a single call (equivalent to: $scope.listTable.push(arrayForUse[0], arrayForUse[1], arrayForUse[2], ...);

The code you have above is pushing an array onto an array:
var arrayForUse = [];
arrayForUse.push({tag:$scope.tagsFeed, instructions:$scope.sublevel.instructions, response:$scope.sublevel.response});
$scope.listTable.push(arrayForUse);
Is this what you want? Your hardcoded test array above seems to indicate you just need an array.

Related

How can I pull a specific title from an array using Angular?

I am trying to pull a specific title from an array using Angular.
Whilst I can use ng-repeat to loop through all titles and print these to my news listing webpage, I only wish to pull the first heading in my array for the news details page. Do I need to use the ng-repeat or can I use something different?
I have tried using number:0 as well as json:0.
$scope.newsListings = [
{
title: "Why cooking is great";
},
{
title: "Windsurfing is fun";
}
];
<div ng-controller="primaryController">
<article>
<div ng-repeat="item in newsListings | json:0">
<h1>{{item.title }}</h1>
<p class="synopsis">{{item.synopsis}}</p>
</div>
<article>
</div>
If you want to show only one item, you can omit the ng-repeat part as you want only one item from your array. You need just to use index.
<div ng-controller="primaryController">
<article>
<div>
<h1>{{ newsListings[0].title }}</h1>
<p class="synopsis">{{ newsListings[0].synopsis }}</p>
</div>
<article>
</div>
You can actually use ng-model for this with a first element of array if you need 2 way binding as well (for inputs of course). For other purposes you can use just index.
<div ng-controller="primaryController">
<article>
<div>
<input type="text" ng-model="newsListings[0].title" />
</div>
<div ng-bind="newsListings[0]">
<h1>{{newsListings[0].title }}</h1>
<p class="synopsis">{{newsListings[0].synopsis}}</p>
</div>
<article>
</div>

Mustache.js is adding text instead of html

It's my first time when I use mustache.js and need some help, please.
Doing a html template builder and I am trying to grab data from JSON and HTML files, than show them into my page.
So I am using this script to get Default theme from JSON than to get the HTML:
$.getJSON('templates.json', function(json){
$.each(json, function(theme, val){
if(theme == 'Default'){
template.load('templates/'+val.url+'/template.html', function(response, status, xhr){
$(this).html(Mustache.render($(this).html(), {
tabs:val.tabs
}));
});
}
});
});
JSON:
{
"Default" : {
"url":"default",
"logo": "YOUR LOGO HERE",
"phone": "+1234567890",
"tabs": [
"About Us",
"Delivery",
"Payment",
"Shipping",
"Contact Us"
]
}
}
HTML:
{{#tabs.length}}
<div id="tabs">
{{#tabs}}
<input class="state" type="radio" title="tab1" name="tabs-state" id="tab1" checked />
{{/tabs}}
<div class="tabs flex-tabs">
{{#tabs}}
<label for="tab1" id="tab1-label" class="tab">{{.}}</label>
{{/tabs}}
{{#tabs}}
<div id="tab1-panel" class="panel active">[[{{.}}]]</div>
{{#tabs}}
</div>
</div>
{{/tabs.length}}
I just can't display the tabs. First time I tried with javascript to convert json into html, but Mustache was showing text instead of html. Now I am trying with conditions in html with no luck.
I also need to add numbers to each item, eg: "tab1", "tab2".. - is this {{#index}} good for that?
How can I add checked only for first items?
Also not sure if {{.}} this is displaying the name of my tab..
You've almost got this nailed, although have slightly misunderstood how to write the mustacheJS view. It's even simpler than you thought! See below. I've simplified the example, so you understand the concept.
Some explanation for below:
{{#Default}}{/Default}} represents looping over an object literal
{{#tabs}}{{/tabs}} presents looping over the object that exists within {{#Defaults}}.
{{.}} displays the entire contents of the object. If this was a complex object, it would be rendered as [object][object]. If you ever encounter this, you must name the object explicitly in your view.
<div class="tabs">
{{#Default}}
{{#tabs}}
<input class="state" type="radio" title="Tab1" name="tabs-state" checked/>
<div class=tabs flex-tabs>
{{.}}
</div>
{{/tabs}}
{{/Default}}
</div>
View Produced
<div class="tabs">
<div class=tabs flex-tabs>
About Us
</div>
<div class=tabs flex-tabs>
Delivery
</div>
<div class=tabs flex-tabs>
Payment
</div>
<div class=tabs flex-tabs>
Shipping
</div>
<div class=tabs flex-tabs>
Contact Us
</div>
</div>

Data bind over in array in knockoutjs

I have an array as follows:
self.arrayObj : Array[2]
>0:Object
>Display1
->InnerObjects
>__proto
>1:Object
>Display2
-->InnerObjects
My interntion is to display "Display1" and "Display2" which are strings
I am doing the html binding as follows:
<div data-bind="foreach: self.arrayObj">
<span data-bind="text:$data[0]"></span>
</div>
How can I iterate over the array and display only texts?
In case your array is just an array of strings you should do the following:
<div data-bind="foreach: self.arrayObj">
<span data-bind="text:$data"></span>
</div>
In case your array is an array of objects which have for example a property 'Name', which is a string, then you do it like this. Knockout knows you're inside the foreach so it knows which element you're at while looping.
<div data-bind="foreach: self.arrayObj">
<span data-bind="text:Name"></span>
</div>
I would like to answer my own question.
It is not a simple thing when we want to bind the object with dynamic keys and values in the UI using Knockout js. If we have the fixed keynames then its easy.
What I did was , converted the json object to 2-D array :
In the .js file
var 2Darray = jsonObject.map(function(val) {
var keyname = Object.keys(val)[0];
var value = val[keyname];
return [keyname,value];
});
In the html file , we can bind it two times in a loop:
<div data-bind:"foreach:2Darray">
<div data-bind:"foreach: $data">
<div data-bind:"text:$data[0]">
<div data-bind:"foreach: $data[1]">
<div data-bind:"text:$data.val">
</div>
</div>
</div>

knockout condition in HTML page

Below is my HTML binding to display the records. I, have apply knockout js to perform the condition check as you can see the IF statement.
I want to use count++ as a knockout variable and perform the condition check.
The above code also not working for me.
Please can anyone let me know how to check the condition in knockout.
<div data-bind="foreach: GuidelinesQuestionList" id="problemcollapse">
<div data-bind="foreach: $data.SectionsSet">
<div class="primaryCaseContainer">
<div class="questionHeader" data-bind="text: $data.Heading , attr:{onClick: 'variableName.CollapseExpandCustom.ToggleSection(\''+$data.Uid.replace(/[^\w\s]/gi, '')+'\')'}"></div>
<div data-bind="attr: {id: $data.Uid.replace(/[^\w\s]/gi, '')}">
#{int count = 0;}
<div class="questionContainer" data-bind="foreach: $data.ProblemsSet">
<div data-bind="if: $data.Identified">
#{count++;}
<div>
<br><br>
<div data-bind="attr: {id: 'goalsReplaceDiv'+$data.Uid.replace(/[^\w\s]/gi, '')}"></div>
</div>
</div>
</div>
#if (count == 0)
{
<div id="divNoRecordsMessage">
<div>No Records !! </div>
</div>
}
</div>
</div>
</div>
</div>
You are mixing C# razor code with Knockout bindings. The count variable will not increment in your loop because it's evaluated before being returned to the client. Your loop is being rendered on the client.
Instead of doing that, make your divNoRecordsMessage show/hide based on a KO binding.
Something like this:
<div data-bind="visible: conditionForNoRecords">
No Records
</div>
But you should really make a custom filter for the ProblemSet array, something like this:
self.filteredProblemsSets = ko.computed(function() {
return ko.utils.arrayFilter(this.ProblemsSet(), function(item) {
return item.Identified;
});
}, viewModel);
You could then skip your if condition in the view and you would be able to easily display "No messages" when the array is empty.

Counting objects that contain specific property in AngularJS

I'm trying to read stats out of an array of objects that looks like this:
{
"time":"19.09",
"car":"429",
"driver":"Julia",
"from":"James Hotel",
"destination":"Juba Teaching Hospital",
"pax":"2",
"arrival":"19.09",
"inserted":true
}
{
"date":"25/10/2014",
"time":"19.11",
"car":"396",
"driver":"Tom",
"from":"Drilling company",
"destination":"James Hotel",
"pax":"2",
"comment":"This comment is a test",
"commenttime":"19.11",
"arrival":"19.12",
"inserted":true
}
I'm using the Unique module from AngularUI to be able to make a list of all drivers or all cars, which so far works OK and creates the following table:
<div class="row msf-stats-data-row" >
<div class="col-md-5">
<div class="row" ng-repeat="record in recordlist | unique:'car'">
<div class="col-md-4">{{record.car}}</div>
<div class="col-md-4">Trips</div>
<div class="col-md-4">Time on the road</div>
</div>
</div>
<div class="col-md-6 pull-right">
<div class="row" ng-repeat="record in recordlist | unique:'driver'">
<div class="col-md-6">{{record.driver}}</div>
<div class="col-md-2">Trips</div>
<div class="col-md-4">Time on the road</div>
</div>
</div>
</div>
Every object is a trip. My problem right now is that I want to be able to both count how many objects contain each of the unique record.car or record.driver properties (to be able to determine how many trips a car took), and also to make operations with momentJS to be able to determine how much time a particular car or driver was on the road (timeOnRoad = record.time - record.arrival).
I'm a bit lost on whether this is even possible to do.
Any input?
ANSWER
The answer from Ilan worked perfectly! Here's my code after I adapted it slightly.
var carsDict = {};
angular.forEach($scope.recordlist, function(record) {
carsDict[record.car] = carsDict[record.car] || [];
carsDict[record.car].push(record);
});
$scope.carstats = carsDict;
And the HTML:
<div class="col-md-5">
<div class="row" ng-repeat="carcode in carstats">
<div class="col-md-4">{{carcode[0].car}}</div> <!-- Car code -->
<div class="col-md-4">{{carcode.length}}</div> <!-- NÂș of objects (trips) inside carcode -->
<div class="col-md-4">Time on the road</div>
</div>
</div>
First create a dictionary of cars to store references of records per car.
var carsDict = {};
angular.forEach(recordlist, function(record) {
carsDict[record.car] = carsDict[record.car] || [];
carsDict[record.car].push(record);
});
Then you can make all calculations for each car.

Categories