How to target ng-show on specific items in ng-repeat? - angularjs

http://plnkr.co/edit/aiGCPJEwTj0RWnuoCjsW?p=preview
I want the remove button to only show the popover for that item.
How would you go about this?
HTML:
<li ng-repeat="acc in accounts">
<div class="well well-sm">
<div class="popover-remove" ng-show="popoverRemove">Click to remove item</div>
<h4>{{acc.label}}</h4>
<button class="btn btn-default"
ng-mouseover="showPopover()"
ng-mouseleave="hidePopover()">Remove</button>
</div>
</li>
Angular Controller:
var app = angular.module('myApp', [])
.controller('AccountsCtrl',
['$scope',
function($scope) {
var vs = $scope;
vs.accounts = [
{
id: '1',
label: 'Bitage'
},
{
id: '2',
label: 'Blockchain.info'
},
{
id: '3',
label: 'Coinbase wallet'
},
{
id: '4',
label: 'Xapo wallet'
}
];
vs.showPopover = function() {
vs.popoverRemove = true;
};
vs.hidePopover = function() {
vs.popoverRemove = false;
};
}]);

Plunker for you
The thing is that ng-repeat creates it's own scope.So, 'popoverRemove' is the local variable for each scope.You can set true or false to local variable by sending context to controller of that particular element of ng-repeat and set it's value using 'this'.
<button class="btn btn-default"
ng-mouseover="showPopover(this)"
ng-mouseleave="hidePopover(this)">Remove</button>
vs.showPopover = function(context) {
context.popoverRemove = true;
};
vs.hidePopover = function(context) {
context.popoverRemove = false;
};

You can also create a property on each iteration like so:
Instead of calling a function on the scope I simply set the value of well.show to true/false, but you get the jist of the idea!
<li ng-repeat="acc in accounts track by $index">
<div class="well well-sm">
<div class="popover-remove" ng-show="well.show">Click to remove item</div>
<h4>{{acc.label}}</h4>
<button class="btn btn-default"
ng-mouseover="well.show=true"
ng-mouseleave="well.show=false">Remove</button>
</div>
</li>
Plunker updated

Move popOverRemove to each accounts. Then you can control it from each child scope. Update your showPopover/hidePopover as well.
vs.accounts = [
{
id: '1',
label: 'Bitage',
popoverRemove: false
},
{
id: '2',
label: 'Blockchain.info',
popoverRemove: false
},
{
id: '3',
label: 'Coinbase wallet',
popoverRemove: false
},
{
id: '4',
label: 'Xapo wallet',
popoverRemove: false
}
];
I have updated here
http://plnkr.co/edit/uAjhiYTDyXIBmkxAQzzw?p=preview

Related

Skip duplicated items while ng-repeat

There is a nested array which consist of bundles and those bundles in turn have items. So, I want to skip identical item(s) of the next bundle based on previous bundle items while iterating. Below is data model and code snippets:
vm.data
[
{
id: '01',
name: 'Dummy1',
items: [{
id: 'itemOne',
name: 'ItemOne',
desc: 'ItemOne description'
}]
},
{
id: '02',
name: 'Dummy2',
items: [{
id: 'itemOne',
name: 'ItemOne',
desc: 'ItemOne description'
},
{
id: 'otherItem',
name: 'OtherItem',
desc: 'OtherItem description'
}]
},
...
]
Html:
<div ng-repeat="bundle in vm.data track by $index">
...
<ul>
<li ng-repeat="item in bundle.items" ng-if="vm.check(item, $parent.$index)">
<span ng-bind="item.name"></span>
...
</li>
</ul>
</div>
vm.check:
vm.check = function(item, bundleIdx) {
if (bundleIdx > 0) {
return _.some(vm.data[bundleIdx-1].items, function(obj) {
return obj.id !== item.id;
});
} else {
// first bundle, so show all items
return true;
}
};
Demo is here.
It works partially, i.e. second bundle correctly matches conditions, but third bundle not. So, what I'm missing? Any help would be appreciated!
I would keep the complex logic out of your template. Instead you should transform vm.data before you attempt to consume it.
var items = {};
vm.bundles = [];
vm.data.forEach(function(data) {
var bundle = {
id: data.id,
name: data.name,
items: []
};
data.items.forEach(function(item) {
if (!items[item.id]) {
bundle.items.push(item);
}
items[item.id] = true;
});
vm.bundles.push(bundle);
});
Then your template can simply consume the transformed data.
<div ng-repeat="bundle in vm.bundles track by $index">
...
<ul>
<li ng-repeat="item in bundle.items">
<span>{{item.name}}</span>
...
</li>
</ul>
</div>

Cannot store drag and drop items in localStorage in angularjs

Hello I am writing a simple aplication to asign tas to the user by using drag and drop option.
(By using angular-dragdrop.min.js file).
I can keep data in local storage but after refresh $$hashKey
automatically changed so even if array is in local storage of the browser so You cannot see item inside user box.
Link to github project
var App = angular.module('drag-and-drop', ['ngDragDrop']);
App.controller('oneCtrl', function($scope) {
$scope.list1 = [];
$scope.list2 = [];
$scope.list3 = [];
$scope.list5 = [
{ 'title': 'Item 1', 'drag': true },
{ 'title': 'Item 2', 'drag': true },
{ 'title': 'Item 3', 'drag': true },
{ 'title': 'Item 4', 'drag': true },
{ 'title': 'Item 5', 'drag': true },
{ 'title': 'Item 6', 'drag': true },
{ 'title': 'Item 7', 'drag': true },
{ 'title': 'Item 8', 'drag': true }
];
var mainList = $scope.list5;
var firstList = $scope.list1;
var secondList = $scope.list2;
var thirdList = $scope.list3;
$scope.doSomething = function () {
localStorage.setItem('mainList', JSON.stringify(mainList));
localStorage.setItem('firstList', JSON.stringify(firstList));
localStorage.setItem('secondList', JSON.stringify(secondList));
localStorage.setItem('thirdList', JSON.stringify(thirdList));
console.log(mainList);
console.log(firstList);
console.log(secondList);
console.log(thirdList);
};
if(localStorage.getItem('mainList')){
$scope.list5.push(JSON.parse(localStorage.getItem('mainList')));
console.log(mainList);
}
if(localStorage.getItem('firstList')){
$scope.list1.push(JSON.parse(localStorage.getItem('firstList')));
console.log(firstList);
}
if(localStorage.getItem('secondList')){
$scope.list2.push(JSON.parse(localStorage.getItem('secondList')));
console.log(secondList);
}
if(localStorage.getItem('thirdList')){
$scope.list3.push(JSON.parse(localStorage.getItem('thirdList')));
console.log(thirdList);
}
And part of index.html
<div class="main-content col-md-12 col-lg-12" ng-controller="oneCtrl">
<div class="btn btn-droppable" ng-repeat="item in list5" data-drop="true" ng-model='list5'
data-jqyoui-options="{accept:'.btn-draggable:not([ng-model=list5])'}"
jqyoui-droppable="{index: {{$index}}}">
<div class="btn btn-info btn-draggable" data-drag="{{item.drag}}"
data-jqyoui-options="{revert: 'invalid'}" ng-model="list5"
jqyoui-draggable="{index: {{$index}},placeholder:true,animate:true}" ng-hide="!item.title">
{{item.title}}
</div>
</div>
<div class="thumbnail" data-drop="true" ng-model='list2' data-jqyoui-options="optionsList2"
jqyoui-droppable="{multiple:true}">
<div class="caption">
<div class="btn btn-info btn-draggable" ng-repeat="item in list2"
ng-show="item.title" data-drag="{{item.drag}}"
data-jqyoui-options="{revert: 'invalid'}" ng-model="list2"
jqyoui-draggable="{index: {{$index}},animate:true}">{{item.title}}
</div>
</div>
</div>
Your issue is with JSON.parse and JSON.stringy.
You should use angular.toJson and angular.fromJson instead as it will strip out the $$hashKey
Example:
//equals to JSON.stringify
localStorage.setItem('mainList', angular.toJson(mainList));
//equals to JSON.parse
if(localStorage.getItem('mainList')){
$scope.list5.push(angular.fromJson(localStorage.getItem('mainList')));
console.log(mainList);
}
UPDATE
This is wrong, you are pushing array into an array so you are create an array of array. Whereas you want an array of objects.
if(localStorage.getItem('firstList')){
//This is what you are doing, this is wrong as this will create
// array of array
$scope.list1.push(angular.fromJson(localStorage.getItem('secondList')));
}
What you should be doing is this
if(localStorage.getItem('firstList')){
//this will assign the array stored in ls to the list1 var
$scope.list1 = angular.fromJson(localStorage.getItem('firstList'));
console.log(firstList);
}

dynamic css active class on ul li reflect according to url changes using angualar js

dynamic css class active applied on li while clickin on li and each li contain link.but if we open a link then dynamic css class active not working properly.
so how can i develop that type of functionality like after book mark perticular li link then when we open that link its need to be selected.
html
<ul>
<li ng-repeat="item in items" ng-class="{'glyphicon glyphicon-menu-down' : item.selected, 'glyphicon glyphicon-menu-right' : !item.selected}" style="display: block;line-height:20px;">
<span ng-click="showChilds($index)">{{item.name}}</span>
<ul>
<li ng-click="showGlyph(subItem);" class="sub-item" id="sub-item-{{$parent.$index}}{{$index}}" ng-class="{'glyphicon glyphicon-envelope' : subItem.active}" ng-repeat="subItem in item.subItems" ng-show="item.selected">
<a ui-sref="{{subItem.url}}">
<span>{{subItem.name}}</span>
</li>
</ul>
</li>
</ul>
javacript controller
$scope.showGlyph = function(subItem) {
angular.forEach($scope.items, function (item) {
angular.forEach(item.subItems, function (sItem) {
sItem.active = false;
});
});
subItem.active = true;
};
$scope.showChilds = function(index){
$scope.items[index].selected= !$scope.items[index].selected;
collapseAnother(index);
};
var collapseAnother = function(index){
for(var i=0; i<$scope.items.length; i++){
if(i!=index){
$scope.items[i].selected = false;
}
}
};
$scope.items = [
{
name: "Item1",
subItems: [
{name: "SubItem1" ,url:'user.create'},
{name: "SubItem2" ,url:'user.edit'}
]
},
{
name: "Item2",
subItems: [
{name: "SubItem3",url:'user.new'},
{name: "SubItem4",url:'user.old'},
{name: "SubItem5" , url:'user.newnew'}
]
},
{
name: "Item3",
subItems: [
{name: "SubItem6" , url:'user.oldold'}
]
}
];

ng-repeat not copying correctly over

I have ng-repeat working within a different template, however, I can not get my album.html template to display content. Here is what I have.
app.js
...
.state('album', {
url: '/album',
controller: 'AlbumCtrl as album',
templateUrl: '/templates/album.html'
})
...
AlbumCtrl.js
(function() {
function AlbumCtrl() {
this.albumData = angular.copy(albumPicasso);
};
angular
.module('blocJams')
.controller('AlbumCtrl', AlbumCtrl);
})();
fixture.js (where my object I want to copy lives)
var albumPicasso = {
title: 'The Colors',
artist: 'Pablo Picasso',
label: 'Cubism',
year: '1881',
albumArtUrl: 'assets/images/album_covers/01.png',
songs: [
{ title: 'Blue', duration: 161.71, audioUrl: 'assets/music/bloc_jams_music/blue' },
{ title: 'Green', duration: 103.96, audioUrl: 'assets/music/bloc_jams_music/green' },
{ title: 'Red', duration: 268.45, audioUrl: 'assets/music/bloc_jams_music/red' },
{ title: 'Pink', duration: 153.14, audioUrl: 'assets/music/bloc_jams_music/pink' },
{ title: 'Magenta', duration: 374.22, audioUrl: 'assets/music/bloc_jams_music/magenta' }
]
};
albumt.html (here is my template with ng-repeat)
<main class="album-view container narrow">
<section class="clearfix">
<div class="column half">
<img src="/assets/images/album_covers/01.png" class="album-cover-art">
</div>
<div class="album-view-details column half">
<h2 class="album-view-title">The Colors</h2>
<h3 class="album-view-artist">Pablo Picasso</h3>
<h5 class="album-view-release-info">1909 Spanish Records</h5>
</div>
</section>
<table class="album-view-song-list">
<tr class="album-view-song-item" ng-repeat="album in album.albumData" ng-mouseover="hovered = true" ng-mouseleave="hovered = false">
<td class="song-item-number">
<span ng-show="!playing && !hovered"></span>
<a class="album-song-button" ng-show="!playing && hovered"><span class="ion-play"></span></a>
<a class="album-song-button" ng-show="playing"><span class="ion-paused"></span></a>
</td>
<td class="song-item-title">{{ album.songs.title }}</td>
<td class="song-item-duration">{{ album.songs.duration }}</td>
</tr>
</table>
</main>
<ng-include src="'/templates/player_bar.html'"></ng-include>
{{ album.songs.title }} and {{ album.songs.duration }} isn't displaying any content nor am I receiving any errors. I personally believe I am not copying my object through my controller correctly? Further, how can I see my input of said object through my controller to test whether my object albumPicasso was copied correctly?
For Reference
This controller (CollectionCtrl.js) is working correctly and mirrors what I want to do besides the for loop.
(function() {
function CollectionCtrl() {
this.albums = [];
for (var i=0; i < 12; i++) {
this.albums.push(angular.copy(albumPicasso));
}
}
angular
.module('blocJams')
.controller('CollectionCtrl', CollectionCtrl);
})();
album in album.albumData
May be you want to not override album variable name?
Controller alias is just variable in scope. You are overwriting it.
It looks like:
for (var i = 0; i < album.albumData.length; i++) {
album = album.albumData[i]; // <-- We brake all things here
}
Just rename album in ngRepeat to something like item:
ng-repeat="item in album.albumData"
Also, you want iterate a songs array, not an object:
ng-repeat="song in album.albumData.songs"
and
{{song.title}}
albumPicasso doesn't seem to be a global variable so it seems it's not accessible from AlbumCtrl.js. Try setting this.albumData to some dummy data.
I would personally create an angular service that provides the album data and inject it in the controller.
you can create a service for this
(function() {
var albumPicasso = {
title: 'The Colors',
artist: 'Pablo Picasso',
label: 'Cubism',
year: '1881',
albumArtUrl: 'assets/images/album_covers/01.png',
songs: [{
title: 'Blue',
duration: 161.71,
audioUrl: 'assets/music/bloc_jams_music/blue'
}, {
title: 'Green',
duration: 103.96,
audioUrl: 'assets/music/bloc_jams_music/green'
}, {
title: 'Red',
duration: 268.45,
audioUrl: 'assets/music/bloc_jams_music/red'
}, {
title: 'Pink',
duration: 153.14,
audioUrl: 'assets/music/bloc_jams_music/pink'
}, {
title: 'Magenta',
duration: 374.22,
audioUrl: 'assets/music/bloc_jams_music/magenta'
}]
};
function fixtureService() {
this.getAlbumData = function(){
return albumPicasso;
};
}
angular
.module('myApp')
.service('fixtureService', fixtureService);
})();
and this service can be injected into your controller
(function() {
function AlbumController(fixtureService) {
this.albumData = fixtureService.getAlbumData();
console.log(this.albumData);
}
angular
.module('myApp')
.controller('AlbumController',['fixtureService', AlbumController]);
})();

How to parse model data in the view onto a javascript function in Angular

Assuming I have the following:
<button ng-repeat="{{item in items}}" ng-click="{{item.name}}Function()">{{item.name}}</button>
I need to be able to get the ng-click to dynamically change based on the item.name such as
firstItemFunction()
secondItemFunction()
etc.
If $scope has references to the functions:
$scope.items =
[
{ name: 'firstItemFunction' },
{ name: 'secondItemFunction' }
];
$scope.firstItemFunction = function () {
console.log('firstItemFunction');
};
$scope.secondItemFunction = function () {
console.log('secondItemFunction');
};
HTML:
<button ng-repeat="item in items" ng-click="this[item.name]()">
{{item.name}}
</button>
Demo: http://plnkr.co/edit/FSrGumlZqm4Rdku6I3X5?p=preview
Alternatively:
$scope.items = [{
name: 'firstItemFunction'
}, {
name: 'secondItemFunction'
}];
$scope.firstItemFunction = function() {
console.log('firstItemFunction');
}
$scope.secondItemFunction = function() {
console.log('secondItemFunction');
}
$scope.execute = function(action) {
$scope[action]();
};
And:
<button ng-repeat="item in items" ng-click="execute(item.name)">
{{item.name}}
</button>
Demo: http://plnkr.co/edit/6jATpgEAvFgTFXbvQ6IE?p=preview
If the functions are defined globally use HTML from above, inject $window and:
$scope.items = [{
name: 'firstItemFunction'
}, {
name: 'secondItemFunction'
}];
$scope.execute = function(action) {
$window[action]();
};
Demo: http://plnkr.co/edit/TinMbmvMTIQS4vptQMYf?p=preview
I would move the logic for determining which function to call to your javascript.
html
<button ng-repeat="{{item in items}}" ng-click="figureOutFunction(item)">{{item.name}}</button>
javascript
$scope.figureOutFunction(item){
if(item.name == "firstItem"){
firstItemFunction();
}
else if(item.name == "secondItem"){
secondItemFunction();
}
};
edit
If you want to avoid the switch, you can do it this way:
html
<button ng-repeat="{{item in items}}" ng-click="item.action()">{{item.name}}</button>
javascript
var firstItemFunction = function(){
...
};
var secondItemFunction = function(){
...
};
$scope.items = [{
name: 'firstItem',
action: firstItemFunction
}, {
name: 'secondItem',
action: secondItemFunction
}];
I would avoid creating unnecessary functions that call others.

Resources