creating property dynamically in ng-model - javascript

<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}];
})

Related

AngularJS creating json from ng-repeat

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

Checkbox is not working properly with ng-repeat, AngularJs

I want to make multiselect checkbox using ng-repeat. It is working fine if I don't have pre-selected checkbox. But when I have preselected checkbox then its behaviour is totally unusual.
<div ng-repeat="account in accounts">
<input ng-model="selectedAccounts[account.id]"
ng-checked="{{account.lastchecked}}" type="checkbox">
</div>
In Controller I got selected id as:
$scope.selectedAccounts = [];
angular.forEach($scope.selectedAccounts, function(value, key) {
if(value == true) {
selectedIds.push(key);
}
});
The problem here is that I have to initialise selectedAccounts with initial array. If I don't do this then it gives me undefined. When I have 'lastchecked' true for some accounts then it shows pre-checked values according to lastchecked but when I try to retreive $scope.selectedAccounts it give me empty array. But when I manually check/uncheck each option then $scope.selectedAccounts give me correct result.
Here is how i would do it :
$scope.context = {accounts : :[]};// init is important to place the variable in that scope on not in a child
<div ng-repeat="account in context.accounts">
<input ng-model="account.lastchecked" ng-checked="account.lastchecked"
ng-true-value="true" ng-false-value="false" type="checkbox">
</div>
Ng-true-value and ng-false-value ensure that the value will be the boolean true/false instead of strings.
After to get the selectedAccount you just search.filter account with lastchecked==true
The indermediary object context is to avoid scope issues, scope inheritance fails on simple fields. This is a limit of javascript. In angularJS this is called DOT notation.
Go through this
var jimApp = angular.module("mainApp", []);
jimApp.controller('mainCtrl', function($scope){
$scope.selectedAccounts = {"3":true};
$scope.accounts = [{id:1, name:"account1", checked: true}, {id:2, name:"account2"}, {id:3, name:"account3"}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="mainApp" ng-controller="mainCtrl">
<div ng-repeat="account in accounts">
<input ng-model="selectedAccounts[account.id]"
ng-checked="selectedAccounts[account.id]" type="checkbox">{{account.name}}
</div>
<div>{{selectedAccounts}}</div>
</div>

Filter separate variable in Angular

So I have some code that looks like this:
<input ng-model="search" type="text">
<td ng-repeat="key in targets">
{{ display_names[key] }}
</td>
To be more clear:
targets is a variable containing not-human readable ids such as key012
display_names is an object which has keys like: key012: "USA"
I would like to filter the display_names value from the search? Looking at the angularjs docs, I know I can filter key, but I haven't figured out how to filter display_names
Example
Here's a full example:
var TS = angular.module('myapp', []);
TS.controller('test', function($scope) {
$scope.targets = ["id_1", "id_2"];
$scope.display_names = {
"id_1": "USA",
"id_2": "Mexico"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myapp" ng-controller="test">
<input ng-model="search" placeholder="Search...">
<ul>
<li ng-repeat="key in targets">{{display_names[key]}}</li>
</ul>
</body>
<td ng-repeat="key in targets">
<span ng-if="display_names[key].indexOf(search) > -1">{{ display_names[key] }}</span>
</td>
use ng-if, or you could also use ng-show. Differences here
This way, as you write in search (which should be in $scope.search) angular will refresh the ng-repeat values to show
If you want to search it case-insensitive, you could use toLowerCase() function before using indexOf
display_names[key].toLowerCase().indexOf(search) > -1
You can't use a filter | in the html because you don't have the value you want to filter against in the array you are iterating over. Instead you can use ng-if to show/hide the elements based on the search. Something like:
<div ng-repeat="key in targets" ng-if="!search || !!display_names[key].match(search)">
{{ display_names[key] }}
</div>
The !! boolean cast is done because otherwise a new Regex object will be returned for the match which triggers a digest cycle which will return another new object and so on.
You also probably want to iterate over <tr> rather than <td>, and you need a <table> element for these elements to be allowed.
Example: http://plnkr.co/edit/qrpLKD9x4IBXowpIgnrf?p=preview
You could also write a custom filter for this, but it is a lot more work:
.filter('displayNames' function () {
return function (key, names, search) {
return !search || !!names[key].match(search);
};
});
And use it like key in targets | displayNames:display_names:search

How to add multiple items to a list

I'm building an app where users can add items to a list and I decided, for the sake of learning, to use Angular (which I'm very new to). So far, I've been able to successfully add a single item to that list without any issues. Unfortunately, whenever I try to add more than one without a page refresh, I get an error - specifically a "Undefined is not a function."
I've spent more time than I care to think about trying to resolve this issue and I'm hoping an expert out there can give me a hand. Here's what I have so far:
Controllers:
angular.module('streakApp')
.controller('StreakController', function($scope) {
// Removed REST code since it isn't relevant
$scope.streaks = Streak.query();
// Get user info and use it for making new streaks
var userInfo = User.query(function() {
var user = userInfo[0];
var userName = user.username;
$scope.newStreak = new Streak({
'user': userName
});
});
})
.controller('FormController', function($scope) {
// Works for single items, not for multiple items
$scope.addStreak = function(activity) {
$scope.streaks.push(activity);
$scope.newStreak = {};
};
});
View:
<div class="streaks" ng-controller="FormController as formCtrl">
<form name="streakForm" novalidate >
<fieldset>
<legend>Add an activity</legend>
<input ng-model="newStreak.activity" placeholder="Activity" required />
<input ng-model="newStreak.start" placeholder="Start" type="date" required />
<input ng-model="newStreak.current_streak" placeholder="Current streak" type="number" min="0" required />
<input ng-model="newStreak.notes" placeholder="Notes" />
<button type="submit" ng-click="addStreak(newStreak)">Add</button>
</fieldset>
</form>
<h4>Current streaks: {{ streaks.length }}</h4>
<div ng-show="newStreak.activity">
<hr>
<h3>{{ newStreak.activity }}</h3>
<h4>Current streak: {{ newStreak.current_streak }}</h4>
<p>Start: {{ newStreak.start | date }}</p>
<p>Notes: {{ newStreak.notes }}</p>
<hr>
</div>
<div ng-repeat="user_streak in streaks">
<!-- Removed most of this for simplicity -->
<h3>{{ user_streak.fields }}</h3>
</div>
</div>
Could you post the html of StreakController too? Your solution works fine in this fiddle:
http://jsfiddle.net/zf9y0yyg/1/
.controller('FormController', function($scope) {
$scope.streaks = [];
// Works for single items, not for multiple items
$scope.addStreak = function(activity) {
$scope.streaks.push(activity);
$scope.newStreak = {};
};
});
The $scope inject in each controller is different, so you have to define the "streaks" in FormController.
Your problems comes from :
.controller('FormController', function($scope) {
// Works for single items, not for multiple items
$scope.addStreak = function(activity) {
$scope.streaks.push(activity);
^^^^^^
// Streaks is initialized in another controller (StreakController)
// therefore, depending of when is instantiated StreakController,
// you can have an error or not
$scope.newStreak = {};
};
});
A better design would be to implement a StreakService, and to inject that service in the controller you need it. Of course, initializing $scope.streaks in FormController will make your code work, but that's not the responsibility of FormController to initialize this data.
I assume FormController is a nested controller of StreakController, so they share the same scope.
if that works for single object, it should work for mulitiple objects, the problems is you can't just use push to push an array of object to the streaks, you can for loop the array and add them individually or use push.apply trick. I thought the reason of Undefined is not a function. is because the Stack.query() return an element instead of an array of elements so, the method push doesn't exists on the $scope.streaks.
http://jsbin.com/jezomutizo/2/edit

Angular ng-class performance issue when too many elements in DOM

I have been working on a complex angular page which has been causing performance issue. To highlight the problem I have created a fiddle http://jsfiddle.net/4ex2xgL1/3/ here.
Essentially the performance issue is being caused by ng-class statement which has a function in it.
<span class="done-{{todo.done}}" ng-class="myfunction()">{{todo.text}}</span>
The span is in an ng-repeat. On running the fiddle one can see that ng-class gets executed several times when the page loads and on each key up it gets called as many time as number of items in the TODO list.
This is a lot simpler case, in my case I have 780 items on my page and the function ends up being evaluated aroung 3000 times!
One of the solution we saw is to break up the scope but it will cause almost a rewrite of my app.
We also tried https://github.com/Pasvaz/bindonce but it doesn't seem to be working with highly dynamic content.
Any thoughts?
I built a tree with https://github.com/JimLiu/angular-ui-tree with almost 500 items to render, with quite a lot of listeners. It takes 5 seconds to render. Bindonce won't work there.
The only solution out there is make ng-repeat do less. Keep the list small with a pagination, search or anything. Its the best shot as far as I know.
Well here are my recommendations
use ng-change on the checkbox to manipulate dom or anything rather using ng-class, it will improve your performance drastically.
<li ng-repeat="todo in todos track by todo.id">
<input type="checkbox" ng-model="todo.done" ng-change="myfunction()">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
http://jsfiddle.net/4ex2xgL1/3/
use track by in ng-repeat if you have ids, more here http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/
dont show 780 items in a list. Use a searchbox to show some 100 or 50 or you know better
quick-ng-repeat not used yet, try testing it https://github.com/allaud/quick-ng-repeat
finally a few good http://tech.small-improvements.com/2013/09/10/angularjs-performance-with-large-lists/
Finally I found the solution and it will helps lot to improve performance in angular js.
If your model changes dynamically and if you have lots of data and then also it improve AngularJS pages rendering up to 1000% and more - no kidding !.
Fore more information you can visit : http://orangevolt.blogspot.in/2013/08/superspeed-your-angularjs-apps.html
Follow the steps:
download the library from the link:library
2.example without library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
};
$scope.getEntries = function() {
console && console.log( "getEntries() called");
return entries;
};
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries() | orderBy:order">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>
3.example with library:(check your console)
function MyController( $scope) {
var entries = [
{ label : 'one', value : 'first entry'},
{ label : 'two', value : 'second entry'},
{ label : 'three', value : 'third entry'}
];
$scope.label ="";
$scope.value ="";
$scope.order = 'label';
$scope.add = function() {
entries.push({
label : $scope.label,
value : $scope.value
});
// clear cache
$scope.getEntries.cache = {};
};
$scope.getEntries = _.memoize(
function() {
console && console.log( "getEntries() sorted by '" + $scope.order + " 'called");
// return entries sorted by value of $scope.order
return _.sortBy( entries, $scope.order);
},
function() {
// return the cache key for the current result to store
return $scope.order;
}
);
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form name="myform" ng-app ng-controller="MyController">
Label/Value :
<input type="text" required ng-model="label">
<input type="text" required ng-model="value">
<button
ng-disabled="!myform.$valid"
ng-click="add()"
>Add</button>
<fieldset>
<legend>
Entries sorted by
<select
ng-model="order"
ng-options="property for property in [ 'label', 'value']">
</select>
</legend>
<div ng-repeat="entry in getEntries()">
{{entry.label}} = "{{entry.value}}"
</div>
</fieldset>
</form>

Categories

Resources