ng-model with unique id inside ng-repeat ionic 1 angularjs - javascript

I want to create like button with ionic 1/angular js.
The problem is when like buttons doesnt work with ng-model within ng-repeat because all ng-model have same names.
This is the html so far.
<div ng-repeat="item in items">
<div class = "item item-text-wrap">
<button class="button button-block icon ion-thumbsup" ng-model="islike" ng-class="islike== true?'button-on':'button-light'" ng-click="changeLikeState(item.id);"> Like</button>
</div>
</div>
I want to initialize the button state if a user already like this item or not. If user already like the item, islike is set to true otherwise islike set to false.
I want to create a function to check like state with $http.get call and set the islike based on the results
The problem is there are multiple item with same islike, How do you set item.id within ng-model="islike" to identify specific button?
Is this the correct approach ? How to solve this in ionic/angularjs?

You don't need an ng-model for buttons. Simply pass the object into your function with ng-click to trigger any changes there. Here is a demo:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.items = [
{"islike":false,"id":1},
{"islike":false,"id":2},
{"islike":false,"id":3},
];
$scope.changeLikeState = function(item) {
item.islike = !item.islike;
console.log(item.id);
}
});
.button-on {
color: blue;
font-weight: bold;
}
.button-light {
color: green;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="item in items">
<button ng-class="{'button-on':item.islike,'button-light':!item.islike}" ng-click="changeLikeState(item);">
Like
</button>
</div>
</div>

as pointed above in the comment islike should be a property of each item in your object, for example :-
let's assume your collection looks something like
$scope.items = [{ name: 'pan cakes', islike: false },
{ name: 'pea nut butter', islike: true },
{ name: 'pizza', islike: true }]
along with other properties if there's an id associated too, that's more than enough otherwise you can always use the $index in ng-repeat to track the current item in items
your code then may look something like this:-
<div ng-repeat="item in items track by ($index)">
<div class = "item item-text-wrap">
<button class="button button-block icon ion-thumbsup" ng-model="item.islike" ng-class="item.islike == true?'button-on':'button-light'" ng-click="changeLikeState($index);"> Like</button>
</div>
</div>
notice the change track by and instead of islike its not item.islike

Related

AngularJS: my Accordion expands, but does not collapse

I have an accordion object in AngularJS that is data driven. Here is what my html looks like:
HTML:
<div class="field-accordion" ng- if="field.fieldAccordion">
<ul class=a ccordion>
<li ng-repeat="fieldAccordion in field.fieldAccordion" ng- click="accordion.current = fieldAccordion.fieldName">
{{ fieldAccordion.fieldName }}
<ul ng-show="accordion.current == fieldAccordion.fieldName">
<li ng-repeat="fieldSub in fieldAccordion.fieldSub">
{{fieldSub.fieldName}}
</li>
</ul>
</li>
</ul>
</div>
Then in my JS file, I simply use it like this:
JS:
app.controller("myCtrl", function($scope) {
$scope.mySettings({
Header: '',
Title: '',
Img: '',
fieldAccordion: [{
// "this is my accordion list"
This works great for me. Whenever I click on the parent, it expands. The problem that I'm having is I can't get it to collapse. I am also trying to do it while keeping everything data driven like it is now. Is there anything I can change in my HTML to allow the text to collapse after expanding ?
Thank you
So the problem is because of a new scope being created, what you need to know is ng-if and ng-r creates a new scope, I checked your code and the ng-repeat is the root cause of the issue! hence the variable is not updating and the accordion is not toggling. Here is a simple way to update the parent controller using the $parent.
I have created a mockup highlighting the issue. So instead of updating accordion.current which will update the scope created by the ng-if you can just give it as $parent.accordion.current in the ng-click which will update the parent scope and the variable will be available for the ng-show and the accordion toggling works as expected.
Below is a working snippet, let me know if this fix solved your issue!
var app = angular.module('myApp', []);
app.controller('MyController', function MyController($scope) {
$scope.field = {
Header: '',
Title: '',
Img: '',
fieldAccordion: [{
fieldName: "one",
fieldSub: [{
fieldName: "oneone"
}]
}, {
fieldName: "two",
fieldSub: [{
fieldName: "twotwo"
}]
}]
};
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller='MyController' ng-app="myApp">
<div class="field-accordion" ng-if="field.fieldAccordion">
<ul class="accordion">
<li ng-repeat="fieldAccordion in field.fieldAccordion" ng-click="$parent.accordion.current = fieldAccordion.fieldName">
{{ fieldAccordion.fieldName }}
<ul ng-show="accordion.current == fieldAccordion.fieldName">
<li ng-repeat="fieldSub in fieldAccordion.fieldSub">
{{fieldSub.fieldName}}
</li>
</ul>
</li>
</ul>
</div>
</div>

how to assign array element value to ng-click in angular js

In my program I have an Array which consists of header name and function name.
I am using ng-repeat in a div which consists of a span tag. I want to add different functionality for each iterated span so I stored function name in array.
my html code is:
<div ng-repeat="header in header" ng-init="head=header">
<h4 class="headers">{{ header.name}}</h4>
<div class="arrow-up" ng-show={{ header.arrowup}} ng-click={{header.close}}> </div>
</div>
my angular code is:
$scope.header=[{"name":"Subsection Header #1","arrowup":"arrowup","close":"close()"}];
$scope.close = function() {
console.log(hello);
};
I want to assign close() to the ng-click and arrowup to ng-show. How can I assign them to ng-click and ng-show
change:
<div class="arrow-up" ng-show={{ header.arrowup}} ng-click={{header.close}}>
To:
<div class="arrow-up" ng-show="header.arrowup" ng-click="this[header.close]()">
<button>
CLOSE ME
</button>
</div>
DEMO= http://jsfiddle.net/Lvc0u55v/1788/
ng-click is the problem as i see,
<div class="arrow-up" ng-show="header.arrowup" ng-click="header.close"></div>
we need not give {{}} to ng-click and ng-show.
hope it helps.
First you need to pass a real functions to array:
function arrowUp(){
// ng-show needs to receive true or false
return true;
}
function close(){
// do something here
}
$scope.headers=[{"name":"Subsection Header #1","arrowup":arrowUp,"close":close}];
The bind them in a view:
<div ng-repeat="header in headers">
<h4 class="header">{{ header.name}}</h4>
<div class="arrow-up" ng-show="header.arrowup()" ng-click="header.close()"> </div>
</div>
You need to use the $eval method, you can read more about it here
$scope.$eval Executes the expression on the current scope and returns the result. Any exceptions in the expression are propagated (uncaught). This is useful when evaluating Angular expressions
HTML:
<div ng-controller="TestController">
<div ng-repeat="header in headers">
<h4>{{ header.name}}</h4>
<button type="button" ng-click="onExecuteFunctionFromString(header.close)">Click Here</button>
</div>
</div>
JS:
var myApp = angular.module('myApp', []);
myApp.controller('TestController', ['$scope', function($scope) {
$scope.headers = [{
"name": "Subsection Header #1",
"arrowup": "arrowup",
"close": "close()"
}];
$scope.close = function() {
console.log('hello');
};
$scope.onExecuteFunctionFromString = function(stringFunction) {
$scope.$eval(stringFunction)
};
}]);
Please see working example here

Angular: find parent Objects inside directives

I'm having the following problem:
I want to use a directive at different places in an app and don't want to specify the parent object and directive object every time i use the directive.
Look at this plnkr:
http://plnkr.co/edit/yUoXXZVJmoesIQNhoDDR?p=preview
Its just a $scope.data object that stores a multilevel array.
$scope.data=
[
{"name": "LEVEL0_A", "subitems":
[
{"name":"Level1_A", "subitems":[{"name":"A"},{"name":"B"}]},
{"name":"Level1_B", "subitems":[{"name":"C"},{"name":"D"}]},
...
...
and so on
and there is a little sample custom directive, called deleteItem, that does exactly that.
.directive('deleteItem', function() {
return {
scope:{
item:'=',
parent:'='
},
template: '<ng-transclude></ng-transclude>Delete',
transclude:true,
controller: function($scope){
$scope.deleteItem=function(currentItem,currentParent){
currentParent.subitems.splice(currentParent.subitems.indexOf(currentItem),1);
};
}
};
});
here you see the html template
<body ng-app="myApp">
<div ng-controller="myController">
<div ng-repeat="level0 in data">
<h2>{{level0.name}}</h2>
<div ng-repeat="level1 in level0.subitems">
<div delete-item parent="level0" item="level1">
{{level1.name}}
</div>
--------------------
<div ng-repeat="level2 in level1.subitems">
<div delete-item parent="level1" item="level2">
Name: {{level2.name}}
</div>
</div>
<hr>
</div>
</div>
</div>
</body>
I mean it works, but actually i feel that there must be some way finding the item and parent without specifically linking them to the scope manually.
I'd be really glad if someone could point me in the right direction.
Thanks
Markus
If you do something like this.
$scope.deleteItem=function(currentItem,currentParent){
currentParent.subitems.splice(currentParent.subitems.indexOf(currentItem),1);
};
Then your directive becomes dependent upon the structure of data outside it's scope. That means that the directive can only delete items if it follows exactly that pattern. What if you want to use the delete button on data that isn't from an array?
The better approach is to use the API feature & to execute an expression on the outer scope.
app.directive('deleteItem', function () {
return {
scope: {
remove: '&deleteItem'
},
template: '<ng-transclude></ng-transclude><a ng-click="remove()">Delete</a>',
transclude: true
};
});
When the user clicks "Delete" the remove() API is called and the template handles how that item is removed.
<div ng-repeat="level0 in data">
<h2>{{level0.name}}</h2>
<div ng-repeat="level1 in level0.subitems">
<div delete-item="level0.splice($index,1)">
{{level1.name}}
</div>
--------------------
<div ng-repeat="level2 in level1.subitems">
<div delete-item="level1.splice($index,1)">
Name: {{level2.name}}
</div>
</div>
<hr>
</div>
</div>

Click button to copy text to another div with angularjs

I have a list of Items with different button with them. Plunker
Quick View:
I want something like if I click on any of the buttons, related text will be copy to the div above. Also if I click on the button again it will removed from the Div.Same for each of the buttons. [I added manually one to show how it may display ]
I am not sure how to do that in Angular. Any help will be my life saver.
<div ng-repeat="item in csTagGrp">
<ul>
<li ng-repeat="value in item.csTags">
<div class="pull-left">
<button type="button" ng-class='{active: value.active && !value.old}' class="btn btn-default btn-xs">{{value.keys}}</button>
<span>=</span>
</div>
<div class="pull-left cs-tag-item-list">
<span>{{value.tags}}</span>
</div>
</li>
</ul>
</div>
The simplest thing would be to use $scope.tags object to store selected tags and add/remove them with the scope method similar to this:
$scope.tags = {};
$scope.toggleTag = function(tag) {
if (!$scope.tags[tag]) {
$scope.tags[tag] = true;
}
else {
delete $scope.tags[tag];
}
};
Demo: http://plnkr.co/edit/FrifyCrl0yP0T8l8XO4K?p=info
You can use ng-click to put in your scope the selected value, and then display this value instead of "Win".
http://plnkr.co/edit/IzwZFtRBfSiEcHGicc9l?p=preview
<div class="myboard">
<span>{{selected.tags}}</span>
</div>
...
<button type="button" ng-click="select(value)">{{value.keys}}</button>

How to filter a list in AngularJS using several links

I have been going over a lot of tutorials on how to filter a list and can't find an example for my simple use-case.
I have several buttons such as
Name
Age
Height
I have var persons = {...} object and I display it like
<div ng-repeat="person in persons">
{{person.name...}}
</div>
How do I create a filter so each time I will click on one of the buttons the list will be filtered ?
I have tried addingng-repeat="person in persons | filter:filterPersons"
and on the script side to write:
$scope.filterPersons(person){
if (person.name == "John")
return person;
}
but this is only one use-case (how can I filter by another name?) - in other words - How do I connect the links to the filter?
You can bind your filter to scope variables as you do with any other thing. So all you need is to set the appropriated filter to the scope when the user click and bind it to the ng-repeat filter param. See:
<div ng-app>
<span ng-click="myFilter = {type: 1}">Type 1</span> |
<span ng-click="myFilter = {type: 2}">Type 2</span> |
<span ng-click="myFilter = null">No filter</span>
<ul ng-controller="Test">
<li ng-repeat="person in persons | filter:myFilter">{{person.name}}</li>
</ul>
</div>
function Test($scope) {
$scope.persons = [{type: 1, name: 'Caio'}, {type:2, name: 'Ary'}, {type:1, name: 'Camila'}];
}
Notice that the myFilter is changed when the user clicks the filter, and that it's bound to the ng-repeat filter. Fiddle here. You could also create a new filter, but this solution is far better.
My response is very similar to Caio's. I just wanted to show how to filter out an existing array.
In my ng-repeat I have a search filter that goes through the words. I wanted tabs to look for a string match. So I added a additional filter
<tr class="unEditableDrinks" ng-repeat="drink in unEditableDrinkList | orderBy:'-date'|limitTo:400|filter:search |filter:myFilter">
<td>[[drink.name]]</td>
I only have the top part of my table but this should show the strategy. The second filter called myFilter is attached to the buttons below.
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary" ng-click="myFilter={name:'soda'}">Soda</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary" ng-click="myFilter={name:'energy'}">Energy Drinks</button>
</div>
On each button I am able to add a ng-click that goes through myFilter and searches the td with drink.name. In each ng-click I can set the value of name to search. So every title containing soda or energy can be filtered through.

Categories