How to Iterate over javascript Map using angular ng-repeat - javascript

I'm developing an Angualr application where we have a Map object (as shown below). The key and value of the map object (headerObj) are coming from user as input to the app,
var headerObj = new Map();
headerObj.set(key,value);
I'm iterating through them using foreach as shown below, the output is coming as expected
$scope.inputHeaders.forEach(function (headerkey, headervalue) {
console.log(headerkey, headervalue;
});
but I have to show this map values in UI, which again user can edit, so I have binded them
<li class="list-group-item" ng-repeat="header in inputHeaders">
<div ng-repeat="(key, value) in header">
{{key}} : {{value}}
</div>
</li>
I've googled and tried several ways, but nothing did help, so basically I've wanted to know how can I iterate over a map using forEach in angular?
Just to give more clarity my requirement is something like that: I need values to be passed to the server as key, value pair, only if I'm not wrong, suppose if I use object properties the key of the object will be fixed something like
{"key":"Content-Type","value":"application/x-www-form-urlencoded","$$hashKey":"003"}]
but my server is expecting something like
"Content-Type" => "application/x-www-form-urlencoded"
Created an plunkr edit http://plnkr.co/edit/t2g6Dl831HGyjD6uSdf3?p=preview

AngularJS 1.x does not know how to use Javascript iterators, so you'll have to convert the Map object to an Array first using Array.from().
Controller:
$scope.inputHeadersArray = Array.from($scope.inputHeaders);
View:
<li class="list-group-item" ng-repeat="header in inputHeadersArray">
{{header[0]}} : {{header[1]}}
</li>

you can use :
[...headerObj] or [...headerObj.entries()] to got two dimensions array. and iterate them.
or [...headerObj.keys()] and [...headerObj.values()] for regular array.

here are few changes in your code. http://plnkr.co/edit/gpc1mPsZrl2QVXbnWZKA?p=preview
app = angular.module('testDemo', []);
app.controller('submitCtrl',function($scope) {
$scope.header={};
$scope.inputHeaders=[];
$scope.addHeader = function() {
$scope.inputHeaders.push($scope.header);
$scope.header = {};
$scope.header.key='';
$scope.header.value='';
}
$scope.log=function(){
//alert('in log');
$scope.inputHeaders.forEach(function (key, value) {
console.log(key, value);
});
}
});
HTML:
<body ng-controller='submitCtrl'>
<div >
<input type="text" class="=form-control" ng-model="header.key" placeholder="Key">
<input type="text" class="=form-control" ng-model="header.value" placeholder="value">
<button class="btn btn-sucess" ng-click="addHeader()">Add</button>
<button class="btn btn-sucess" ng-click="log()">Log</button>
<div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="header in inputHeaders">
<!-- need to to work on this logic -->
<div ng-show="inputHeaders.length>=1">
<input type="text" ng-model="header.value" />
<input type="text" ng-model="header.key" />
</div>
</li>
</ul>
</div>
</div>
</body>

Related

AngularJS advice on how to fix a bug when pushing two of the same strings into the array

I'm having trouble trying to figure out how to fix a bug that happens when I try to push the same string as added previously to the array. It gets stuck and will not allow the app to post another string.
How do I make sure that your repeat doesn't get stuck when there two of the same values in the array?
Bug Example Screenshot
--> Bug happens when I try to push "1"into the array again after a "1" is already posted.
HTML Code
<body>
<div data-ng-controller="appController" class="container">
<div class="row">
<form>
<label for = "status"> Status: </label>
<input data-ng-model = "input_data" type="text" id="status"/>
<button data-ng-click="add_data()"> OK </button>
<ul class = "list-group">
<li class="list-group-item" data-ng-repeat="x in array_data">
{{x}}
<button data-ng-click = "remove_data($index)">DEL</button>
</li>
</ul>
</form>
</div>
</div>
<script src="framework/js/jquery.min.js"></script>
<!-- All Bootstrap plug-ins file -->
<script src="framework/js/bootstrap.min.js"></script>
<!-- Basic AngularJS -->
<script src="framework/js/angular.min.js"></script>
<!-- Your Controller -->
<script src="framework/js/appstatpost.js"></script>
</body>
AngularJS code
var app = angular.module("myApp", []);
app.controller("appController", function ($scope) {
$scope.array_data = [];
$scope.add_data = function () {
$scope.array_data.push($scope.input_data);
};
$scope.remove_data = function (index) {
$scope.array_data.splice(index, 1);
};
});
You could use track by $index, example:
<li class="list-group-item" data-ng-repeat="x in array_data track by $index">
AngularJS tries by default to find a key in your array to index by. Normally this works well, but if you have duplicates then you have to tell AngularJS to make a new index, in this case, $index.

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>

How to use ng-repeat in array of objects?

Do you have an idea ?
I tried to make an Array of arrays with ng-repeat like this :
jsfiddle example
function MyCtrl($scope) {
$scope.items =
[
{'adam1': [{id:10, content:test1}, {id:11, content:test2},
{id:12, content:test3}]},
{'adam2': [{id:20, content:test4}, {id:21, content:test5},
{id:30, content:test6}]},
{'adam1': [{id:10, content:xxx}]}
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat="(key, value) in items">{{key}}: {{value.content}}</li>
</ul>
</div>
One way to do that (fiddle):
<div ng-repeat="item in items">
<ul ng-repeat="(key, value) in item">
<li ng-repeat="obj in value">{{obj.content}}</li>
</ul>
</div>
That said you might want to rearrange the structure so as to avoid nested ng-repeat.
Your method of assigning variables works fine, but probably not as you're expecting: updated jsfiddle
The content item will not be available, as value is each object within the main array; you'll need to cycle through their properties (i.e. the adamX keys) to get the nested arrays.

how do I insert a collection into a form in meteor

I am trying to make a basic recipe form that has another form inside it. The inner form uses a collection. I am trying to input that collection into the larger form. I am not sure how to write the code on that particular part.
Ingredients = new Mongo.Collection('ingredients');
Recipe = new Mongo.Collection('recipe');
'submit .recipe_submit': function(event){
Recipe.insert({
recipeServing:event.target.mealserving.value,
recipeIngredients:event.target.,
recipeDirection:event.target.recipedirections.value
})
}
<template name="addingredients">
<h2>Enter Ingredients</h2>
<form class="form-group">
Food Item</span><input name="ingredientType" type="text">
Quantity</span><input name="ingredientQuantity" type="text">
Amount</span><input name="ingredientAmount" type="text" >
<button type="submit">Add</button>
</form>
<div class="col-md-12">
<ul>
{{#each ingredients}}
<li >
<div>
<div>{{this.foodItem}}</div>
<div>{{this.foodQuantity}}</div>
<div>{{this.foodAmount}}</div>
<div class="delete"></div>
</div>
</li>
{{/each}}
</ul>
</div>
</template>
Normally I would use he name="" from the input, but I don't see how this works in this case. I also don't need it to import the delete button either. Any help would be awesome.
Your event needs to extract each value out properly. Here is an example of how you could do it:
Template.addingingredients.events({
'submit .recipe_submit': function(event, template){
Recipe.insert({
recipeType: template.$("input[name=ingredientType]").val(),
recipeQuantity: template.$("input[name=ingredientQuantity]").val(),
recipeAmount: template.$("input[name=ingredientAmount]").val()
})
}
});
I had to rename the keys in your recipe to match the field names, you don't have a 'serving', 'ingredients' or 'direction' elements on your form. I don't think this is what you're looking for in your question, though.
The key point is ff you want to extract a value from an element you can use something like $("input[name=ingredientQuantity]").val() to get the value for an element like <input name="ingredientQuantity" type="text"/>
You can either reference or embed Ingredients inside Recipes. Since the ingredient information is frequently used with the recipe information, I would recommend embedding the Ingredients, but you will first need to grab the ingredients from the inner form with JQuery, which requires distinguishable selectors:
{{#each ingredients}}
<li class="ingredient">
<div class="item">{{this.foodItem}}</div>
<div class="quantity">{{this.foodQuantity}}</div>
<div class="amount">{{this.foodAmount}}</div>
<div class="delete"></div>
</li>
{{/each}}
When the form is submitted, we create an array of Ingredient objects and then embed them as a property of Recipe:
Template.addingingredients.events({
'submit .recipe_submit': function(event, template){
var ingredients = [];
$("li.ingredient").each(function() {
var selector = this;
ingredients.push({
foodItem: $(selector).find(".item").text(),
foodQuantity: $(selector).find(".quantity").text(),
foodAmount: $(selector).find(".amount").text()
});
});
Recipe.insert({
recipeServing: event.target.mealserving.value,
recipeIngredients: ingredients,
recipeDirection: event.target.recipedirections.value
});
}
});

angular custom filter only on button click

I am new to angular custom filters and I was wondering if there was any way to apply the filters to an ng-repeat only when a button is clicked.
Here is a jsfiddle for an example :
http://jsfiddle.net/toddmotto/53Xuk/
<div ng-app="app">
<div ng-controller="PersonCtrl as person">
<input type="text" ng-model="letter" placeholder="Enter a letter to filter">
<ul>
<li ng-repeat="friend in person.friends | startsWithLetter:letter">
{{ friend }}
</li>
</ul>
</div>
</div>
Sometings like this:
function MyController(startsWithLetterFilter) {
//retrieve person object
this.friends = person.friends;
this.onclick = function() {
this.friends = startsWithLetterFilter(person.friends, myLetter);
}
}
Bind the repeater to the friends property and not directed to person.friends so you can manipulate the array responding on some events

Categories