AngularJS checkbox checking when in ng-repeat - angularjs

I know the solution is not very pretty, but it's needed for the template I'm working in.
Now it works, and it shows me the "Added" span-element when the products was in the list.
<section ng-repeat="product in products">
<label>
<input type="checkbox"
checklist-model="foobar.products"
checklist-value="product.id">
{{ product.name }}
</label>
<div ng-repeat="current_item in my.profile.items">
<span ng-show="product.id==current_item.id">Added</span>
</div>
</section>
What I want, it to check the checkbox to checked, when the "Added" text also appeared behind the checkbox.
I tried doing it with:
<ng-checked="{{my.profile.items.array.thing}}">
But that's not working. Because the products in an Array like:
[{
id: 1, name:"Trinity",
id: 2, name:"Van Gogh",
id: 3, name:"Bonaqua",
}]
And the my.profile.items is an array with more info then above. Because it's a many-to-many relation where I stored it.
Is there even a way to do this? I don't mind a dirty solution :P
I tried this:
// NG-check function
$scope.checkStoredValues = function(my) {
// Loop trought my current stored items
angular.forEach(my.profile.items, function(value, key) {
// Loop trough the array
angular.forEach(value, function(value, key) {
console.error(key);
// If key == 'id'
if(key == 'id'){
// Push the value to the Array of the checkboxes,
// so it's checked
// # Docs: http://vitalets.github.io/checklist-model/
console.info(value); // Return's: integer
foobar.products.push(value); // Needs more then an integer I guess..
}
});
});
};
This returns: TypeError: Cannot read property 'push' of undefined

Add this function to your controller:
$scope.isChecked = function(product) {
var items = $scope.my.profile.items;
for (var i=0; i < items.length; i++) {
if (product.id == items[i].id)
return true;
}
return false;
};
And for your html use
<section ng-repeat="product in products">
<label>
<input type="checkbox"
ng-checked="isChecked(product)">
{{ product.name }}
</label>
<div ng-repeat="current_item in my.profile.items">
<span ng-show="product.id==current_item.id">Added</span>
</div>
</section>

Another trick that you can do is create a view model specific for your need.
So for example you have the array of products and items within the profile.
In the controller, you could do something like:
$scope.products.forEach(function(p){
var items = $scope.my.profile.items;
var wasAdded = false;
for (var i=0; i < items.length; i++) {
if (product.id == items[i].id)
wasAdded = true;
i = items.length;
}
$scope.productsViewModels.push({product:p, added:wasAdded});
});
Now that you have created your data as needed in the view, then you can simple do:
<section ng-repeat="p in productsViewModels">
<label>
<input type="checkbox"
ng-checked = "p.added"
checklist-model="foobar.products"
checklist-value="p.product.id">
{{ p.product.name }}
</label>
<span ng-show="p.added">Added</span>
</section>
When I have combined data from multiple sources I prefer to process it before in the controller and create a viewModel that will makes my life easy in the view.

you need to implement something like this AngularJs ng-checked using a function
you just need to implement your own logic based on your many to many product array and return true or false accordingly.

Add this after the checkbox
<span ng-if="my.profile.items.indexOf(product) >= 0">added</span>
and remove the div.

Related

How can I update my radiolist options on the fly in angular?

I'm using a radiolist in a form and need to update the number of option. I load the radiolist in my controller in this way:
//Initialize radiolist for answers
$scope.answersList = [];
$scope.answerSelected = $scope.selectAnsweredSurvey();
for (var i=0; i<$scope.answersCount; i++) {
$scope.answersList.push({value: $scope.answers[i].id, text: $scope.answers[i].text});
}
radiolist in my html form:
<div class="form-group" style="margin-top: 10px;">
<span style="100%"
data-editable-radiolist="answerSelected"
e-ng-options="s.value as s.text for s in ::answersList track by s.value"
e-title="answer.text"
e-ng-disabled="answeredSurvey(survey.id) || !survey.activa">
>
</span>
</div>
In addition I have a 'watch' to detect when the value of $scope.answers changes and return to make the next inside the watch:
for (var i=0; i<$scope.answersCount; i++) {
$scope.answersList.push({value: $scope.answers[i].id, text: $scope.answers[i].text});
}
But the radiolist options do not update.
Thanks
remove double :: from this line. It is used for one way binding, If date get changes in controller it will not get reflected on view. notice e-ng-options="s.value as s.text for s in answersList track by s.value"
https://toddmotto.com/angular-one-time-binding-syntax/
It's not clear from your answer what you are getting from using the radiolist directive, but have you considered just using basic radio buttons?
for example:
<div class="form-group" style="margin-top: 10px;">
<div class="input" ng-repeat="answer in answersList">
<input type="radio" ng-model="radioValue" ng-value="answer.value" ng-disabled="answeredSurvey(survey.id) || !survey.active">
<label>{{answer.text}}</label>
</div>
</div>
This would require no $watch and wouldn't rely on some directive.
Edited to include use of ng-value over value as suggested in comments
The next solve my problem.
First, I adapt my xeditable form like suggested #Sam Bartlett but
I need to add a name attribute, If not, It can select all the options in radiolist.
I need to use a watch wait for change in 'answers'
And very important, in the html, the ng-model need '$parent.' before the answerSelected, If not, I can not access to this variable.
My controller:
//Initialize radiolist for answers
$scope.answerSelected = null;
$scope.answersList = [];
for (var i=0; i<$scope.respuestasCount; i++) {
$scope.answersList.push({value: $scope.answers[i].id, text: $scope.answers[i].text});
}
//watch for answers
$scope.$watch('answers', function watcher(valueNew, valueOld) {
if (valueNew !== valueOld) {
var answersCount = $scope.answers.lenght;
$scope.anwersList = [];
for (var i=0; i<answersCount; i++) {
$scope.answersList.push({value: $scope.answers[i].id, text: $scope.answers[i].text});
}
}
});
My html for radiolist:
<div class="form-group" style="margin-top: 10px;">
<div class="input" ng-repeat="answer in answersList">
<input type="radio"
name="answersSurvey"
ng-model="$parent.answerSelected"
ng-value="answer.value"
ng-disabled="answeredSurvey(survey.id) || !survey.active"
>
<label>{{answer.text}}</label>
</div>
</div>

Angular. Removing in a nested directive with ng-repeat

I'm new to AngularJS and have problem with removing certain element in a nested custom directive with ng-repeat. Here is my plunker
I have such structure of nested directives:
<button ng-click="mc.addCat()">Add Category</button>
<category ng-repeat="cat in mc.main.categories">
<ul class="first-level">
{{ $index +1 }}. Category
<br>
<input type="text" ng-model="mc.main.categories[$index].name">
<button ng-click="cc.removeCat($index)">Del Category</button>
<button ng-click="cc.addItem()">Add Item</button>
<item ng-repeat="item in cc.cat.items track by item.id">
<li class="second-level">
{{ $parent.$index +1 }}.{{ $index +1 }}
<input type="text" ng-model="mc.main.categories[$parent.$index].items[item.id].name">
<button ng-click="ic.removeItem(item)">del</button>
</li>
</item>
</ul>
</category>
Adding and removing categories works as I need and the parent model updates.
But when I enter something in the item field, and then remove it, this item remains in the parent model.
I think my issue in nested scopes, could you tell me what am I doing wrong?
Thanks!
the delete function in directive should call a method to update the main model....i have edited the plunker and forked the edit....
`
$scope.$on('updateItems',function(event,index,pindex){
console.log(index);
console.log(pindex);
var sti = ""+index+"";
delete vm.main.categories[pindex].items[sti];
});
`
here is the plunker link plunker
From what i understand from your code is, your new item is being added and you are entering some information which is updating your parent model....
<input type="text" ng-model="mc.main.categories[$parent.$index].items[item.id].name">
While deleting the items, you are deleting the copy and the original object.
$scope.$on('delItem', function(event, data){
var items = vm.cat.items;
items.splice(items.indexOf(data), 1);
});
All the below function in category seems to be not working..
vm.cat = {
items: [{
id: 0,
name: ''
}]
};
vm.itemId = 0;
vm.addItem = function() {
vm.itemId = vm.itemId + 1;
var item = {
id: vm.itemId,
name: ''
};
vm.cat.items.push(item);
};
$scope.$on('delItem', function(event, data) {
var items = vm.cat.items;
items.splice(items.indexOf(data), 1);
});

Resetting form controls after action in Angular

Need a bit of help with this. I am trying to get Angular to reset value of my input box after add control is invoked. This is kind of important when it comes to drop down select boxes. I want to be able to clear what user has selected after the option is pushed to a collection.
I also seems to have an issue with user.fName updating whatever I previously added to the users array but it's probably related to the above.
Also can you see what I am doing wrong with ng-show?
html
<div ng-controller="UserController" name="form">
<div ng-show="form.fName.$touched">Hello {{ user.fName }}</div>
<input type="text" name="fName" ng-model="user.fName">
<a ng-click="addUser(user)">Add</a>
<br>
<div ng-repeat="user in users">{{ user }}</div>
</div>
javascript
function UserController($scope) {
//$scope.user = {
// fName: "Joe",
// lName: "Doe"
//};
$scope.users = [];
$scope.addUser = function (user) {
if($scope.users.indexOf(user) === -1){
$scope.users.push(user);
} else {
// trigger error/notification message
console.log(user, ' already added');
}
user = {}; //clear user
};
}
ngModel will try to bind to the property given by evaluating the expression on the current scope. If the property doesn't already exist on this scope, it will be created implicitly and added to the scope.
You are currently not using the scoped property in your click action but a copy that is passed as a parameter. Change user to $scope.user in your addUser method
Note: your object comparison to identify already added users won't work as you always create new objects that will never match. Change it to some different comparison method like comparing the fName properties.
html
<div ng-controller="UserController" name="form">
<div ng-show="form.fName.$touched">Hello {{ user.fName }}</div>
<input type="text" name="fName" ng-model="user.fName">
<a ng-click="addUser()">Add</a>
<br>
<div ng-repeat="user in users">{{ user }}</div>
</div>
javascript
function UserController($scope) {
$scope.users = [];
$scope.addUser = function () {
if($scope.users.indexOf($scope.user) === -1){
$scope.users.push($scope.user);
} else {
// will never match as indexOf() will always return -1
console.log($scope.user, ' already added');
}
$scope.user = {}; //clear user
};
}
http://plnkr.co/edit/N5FXJdWRl42YrVwJsUuR?p=preview
As for your ng-show question: $touched was introduced in AngularJS 1.3 and you're referencing AngularJS 1.2.x in your Plunker code.

Reversing $index when listing items in reversed order

I stumpled upon this post about how to reverse the display of an array, which is working fine when I try to do it. angular ng-repeat in reverse
However...then itmes I'm listing are editable and when I'm reversing the array the $index is not being reversed so when I edit the 1 item listed the edit happens in another item that holds the correct index.
So how do I make sure that my $index is reversed as well?
So the code looks like this
<form action="" method="post" autocomplete="off" ng-controller="itemCtrl">
<input type="text" name="createitem" ng-model="item" />
<button ng-click="addItem(item)">Add item</button>
<ul>
<li ng-repeat="item in items | reverse">
<h2>{{item.title}}</h2>
</li>
</ul>
</form>
var itemApp = angular.module('itemApp', []);
itemApp.filter('reverse', function() {
return function(items) {
return items.slice().reverse();
};
});
itemApp.controller('itemCtrl', function ($scope) {
$scope.items = [];
$scope.addItem = function(item){
$scope.items.push({
title: item
});
};
Here's what I'm using.
You just need to subtract the array length by the current $index:
{{myArray.length - $index}}

angularjs model reload after item delete

I'm pretty new in angularjs and I have no idea how do this.
<div class="userData" ng-repeat="user in users">
<div class="float"
<img ng-click="deleteUser($event)" src="myurl">
</div>
<div class="userDiv"
<input type="checkbox" ng-model="user.active" ng-click="handleUserActive()">
<input type="text" ng-model="user.text">
</div>
</div>
I need remove a item when the user click the img.
My model is:
$scope.users = [
{active: true, text: text}
]
Just do:
<img ng-click="deleteUser($index)" src="myurl">
And the method:
$scope.deleteUser = function(index) {
$scope.users.splice(index, 1)
}
What tymeJV said, however, you want to pass the object as the parameter rather than the index like this:
<img ng-click="deleteUser(user)" src="myurl">
$scope.deleteUser = function(user) {
var index = $scope.users.indexOf(user);
$scope.users.splice(index, 1)
}
The reason why is the index can change if you do an orderBy on the ng-repeat.
See an example here: http://jsfiddle.net/6a5zT/

Resources