change variable only for one ng-repeat document angularjs - angularjs

I'm trying to show more text when an user clicks a read more button:
<md-content class="md-padding" layout-xs="column" layout="row" layout-wrap>
<div flex-xs flex-gt-xs="50" layout="column" ng-repeat="paquete in paquetes">
<md-card>
<md-card-title layout="row" layout-xs="column">
<md-card-title-media layout-margin>
<img ng-src="{{paquete.img}}" class="md-card-image margin-auto" alt="image caption">
</md-card-title-media>
<md-card-title-text>
<span class="md-headline blue">{{paquete.title}}</span>
<span class="md-subhead dark-blue">{{paquete.desc | limitTo: limit.limit}}
<span class="threedots" ng-show="mas.mas">... </span>
<span style="cursor: pointer;" class="blue underlined"
ng-click="limitFunction(paquete.desc)">Leer
<span class="mas" ng-show="mas.mas">más</span>
<span class="menos" ng-show="menos.menos">menos</span>.
</span>
</span>
</md-card-title-text>
</md-card-title>
</md-card>
</div>
</md-content>
I'm limiting the initial descripction {{paquete.desc | limitTo: limit.limit}} and letting the user click to read more ng-click="limitFunction(paquete.desc)"
My controller:
$scope.limit = {limit: 200};
$scope.limitFunction = function (desc) {
$scope.limit.limit = desc.length;
};
But when I click on one of the ng-repeat elements, the $scope.limit changes to all of them instead of the one I'm clicking.
How do I change the $scope.limit to only the one that I'm clicking?

You could put the limit on the paquete object and pass that into your limit function
<span class="md-subhead dark-blue">{{paquete.desc | limitTo: paquete.limit}}<span class="threedots" ng-show="mas.mas">... </span><span style="cursor: pointer;" class="blue underlined" ng-click="limitFunction(paquete)">Leer <span class="mas" ng-show="mas.mas">más</span><span class="menos" ng-show="menos.menos">menos</span>.</span></span>
In the controller:
$scope.limitFunction = function (paquete) {
paquete.limit = paquete.desc.length;
};

Related

preventing ng-click event with angular-material

I have a series of toggles inside a custom angular dropdown(s). The problem I am having is, the toggles do toggle, but they close the dropdown as well. How can I prevent this? The dropdowns should still close when double clicking the drawer, that is the expected behavior, but not when the toggle is clicked.
This is the HTML:
<div class="cnt" ng-repeat="item in data">
<div class="menu-item" ng-click="toggle(item.pos);">
<md-list layout="row" layout-padding="" class="layout-row" layout-align="start center" flex>
<span class="title flex" flex=""> {{item.name}}</span>
<i class="fa fa-chevron-down" ng-class="{'rotate180': item.pos==menuIsOpen, 'rotate-back': !menuIsOpen}"></i>
</md-list>
<div class="sub-menu" ng-animate="'animate'" >
<div ng-repeat='(k,v) in item track by $index'>
<div ng-if="isArray(v)">
<md-menu-item ng-if="menuIsOpen===item.pos" ng-repeat='v1 in v track by $index'>
<md-button>
<div layout="row" flex="">
<md-switch class="md-primary" name="special" ng-model="project.special" required>
<span class="">
<p flex="">{{v1.title}}</p>
</span>
</md-switch>
</div>
</md-button>
</md-menu-item>
</div>
</div>
</div>
</div>
</div>
and the controller has this in it for functionality purposes and data population from json :
$scope.toggle = function(itemPos) {
if ($scope.menuIsOpen === itemPos) {
$scope.menuIsOpen = 0;
}
else {
$scope.menuIsOpen = itemPos;
}
}
$scope.isArray = function(val) {
return Array.isArray(val);
}
spoiler alert:adding md-prevent-menu-close="true" to the md-button didn't help
Here is a CODEPEN to try things out
Thanks guys
You should move your ng-click="toggle(item.pos);" into the <md-list>
<div class="cnt" ng-repeat="item in data">
<div class="menu-item">
<md-list layout="row" layout-padding="" class="layout-row" layout-align="start center" flex ng-click="toggle(item.pos);">
<span class="title flex" flex=""> {{item.name}}</span>
<i class="fa fa-chevron-down" ng-class="{'rotate180': item.pos==menuIsOpen, 'rotate-back': !menuIsOpen}"></i>
</md-list>
<div class="sub-menu" ng-animate="'animate'" >
<div ng-repeat='(k,v) in item track by $index'>
<div ng-if="isArray(v)">
<md-menu-item ng-if="menuIsOpen===item.pos" ng-repeat='v1 in v track by $index'>
<md-button>
<div layout="row" flex="">
<md-switch class="md-primary" name="special" ng-model="project.special" required>
<span class="">
<p flex="">{{v1.title}}</p>
</span>
</md-switch>
</div>
</md-button>
</md-menu-item>
</div>
</div>
</div>
</div>
</div>

Minimalizing a menu with ng-repeat

I know the question title is a little vague but I don't know what else to call it. Basically, this is my problem:
I have an angular menu with submenus. I have each menu item separate and the submenu items being injected with ng-repeat. That is fine, but the problem is I would like to run the entire menu in one ng-repeat and have the json file hold, not only the submenu items, but the menu items as well. This is what I have:
<div class="cnt">
<div class="menu-item" ng-click="toggle(1); open1=!open1">
<md-list layout="row" layout-padding="" class="layout-row" layout-align="start center" flex>
<span class="title flex" flex=""> Menu Item</span>
<i class="fa fa-chevron-down" ng-class="{'rotate180': open1, 'rotate-back': !open1}"></i>
</md-list>
<div class="sub-menu" ng-animate="'animate'" >
<md-menu-item ng-if="menuIsOpen===1" ng-repeat="item in data" >
<md-button>
<div layout="row" flex="">
<a ui-sref="{{item.link}}">
<p flex=""><i class="fa fa-{{item.icon}}"></i> {{item.title}}</p>
</a>
</div>
</md-button>
</md-menu-item>
</div>
</div>
<div class="menu-item" ng-click="toggle(2); open2=!open2">
<md-list layout="row" layout-padding="" class="layout-row" layout-align="start center" flex>
<span class="title flex" flex=""> Menu Item 2</span>
<i class="fa fa-chevron-down" ng-class="{'rotate180': open2, 'rotate-back': !open2}"></i>
</md-list>
<div class="sub-menu" ng-animate="'animate'" >
<md-menu-item ng-if="menuIsOpen===2" ng-repeat="item in data2">
<md-button>
<div layout="row" flex="">
<a ui-sref="{{item.link}}">
<p flex=""><i class="fa fa-{{item.icon}}"></i> {{item.title}}</p>
</a>
</div>
</md-button>
</md-menu-item>
</div>
</div>
</div>
with a json file that looks like this:
$scope.data =
[{
title: 'Home',
icon: 'home',
link: '/page1/'
}, {
title: 'Email Us',
icon: 'envelope',
link: '/page2/'
}, {
title: 'Profile',
icon: 'user',
link: '/page3/'
}, {
title: 'Print',
icon: 'print',
link: '/page4/'
}];
$scope.data2 =
[{
title: 'Home 2',
icon: 'home',
link: '/page1/'
}, {
title: 'Email Us 2',
icon: 'envelope',
link: '/page2/'
}, {
title: 'Profile 2',
icon: 'user',
link: '/page3/'
}, {
title: 'Print 2',
icon: 'print',
link: '/page4/'
}];
As you can see, if I want 2 menu items, I have to build the code for 2 menu items, add the data to the json, and run the bindings. And if I want 3, then I have to do this 3 times. But what if I want 20? Ideally, I would like to have 1 single HTML structure that pulls the data from the json to create as many menu items with as many submenu items as it finds in the json. But I am having problems trying to achieve this:
This is what makes sense in my head:
<div class="cnt" ng-repeat="item in data">
<div class="menu-item" ng-click="toggle({{item.pos}}); open{{item.pos}}=!open{{item.pos}}">
<md-list layout="row" layout-padding="" class="layout-row" layout-align="start center" flex>
<span class="title flex" flex=""> {{item.name}}</span>
<i class="fa fa-chevron-down" ng-class="{'rotate180': open{{item.pos}}, 'rotate-back': !open{{item.pos}}}"></i>
</md-list>
<div class="sub-menu" ng-animate="'animate'" >
<md-menu-item ng-if="menuIsOpen==={{item.pos}}" >
<md-button>
<div layout="row" flex="">
<a ui-sref="{{item.item1[0].linkto}}">
<p flex=""><i class="fa fa-{{item.icon}}"></i> {{item.item1[0].title}}</p>
</a>
</div>
</md-button>
</md-menu-item>
</div>
</div>
</div>
I have a CODEPEN that you can see the working code in.
See this CODEPEN for the desired effect. This is how I have it working now and how it should work ultimately.
Thanks fellas!
This answer is not directly addressing the parsing issue, but a solution to what you are trying to achieve.
Instead of using open{{item.pos}} to identify the menu item, which is resulting in parsing error, use the the menuIsOpen,which holds the position of the toggled item. Based on the desired effect.. codepen sample
script additions
//Not needed
// $scope.open1 = false; //initial value
//$scope.open2 = false; //initial value
//$scope.open3 = false; //initial value
//$scope.open4 = false; //initial value
$scope.toggle = function(itemPos) {
if ($scope.menuIsOpen === itemPos) {
$scope.menuIsOpen = 0;
}
else {
$scope.menuIsOpen = itemPos;
}
}
html : just need toggle the item we pass the position property
<div class="cnt" ng-repeat="item in data">
<div class="menu-item" ng-click="toggle(item.pos);">
<md-list layout="row" layout-padding="" class="layout-row" layout-align="start center" flex>
<span class="title flex" flex=""> {{item.name}}</span>
<i class="fa fa-chevron-down" ng-class="{'rotate180': item.pos==menuIsOpen, 'rotate-back': !menuIsOpen}"></i>
</md-list>
<div class="sub-menu" ng-animate="'animate'" >
<md-menu-item ng-if="menuIsOpen===item.pos" >
<md-button>
<div layout="row" flex="">
<a ui-sref="{{item.item1[0].linkto}}">
<p flex=""><i class="fa fa-{{item.icon}}"></i> {{item.item1[0].title}} a</p>
</a>
</div>
</md-button>
</md-menu-item>
</div>
</div>
</div>
Let us know
Update : based on your comment, the current setup only deals with item at postion 0 (only 1 item). The JSON (if you do not have control) and you need the item1 item2 etc.. to be displayed you can extend the ng-repeat by going over the entire object and iterate ONLY the ARRAYS. This is not going for the optimal solution just a work around.. sort of..
If there is another array of links inside the array.. this solution will not work.
html
<div class="sub-menu" ng-animate="'animate'" >
<div ng-repeat='(k,v) in item track by $index'>
<div ng-if="isArray(v)">
<md-menu-item ng-if="menuIsOpen===item.pos" ng-repeat='v1 in v track by $index'>
<md-button>
<div layout="row" flex="">
<a ui-sref="{{v1.linkto}}">
<p flex=""><i class="fa fa-{{v1.icon}}"></i> {{v1.title}}</p>
</a>
</div>
</md-button>
</md-menu-item>
</div>
</div>
</div>
script
$scope.isArray = function(val) {
return Array.isArray(val);
}

How to use ng-show and ng-hide in ng-repeat loop

Here i have the code:
<ul dnd-list="list" ng-controller="Modalcontrol">
<li ng-repeat="item in list" ng-click="showAdvanced($event)">
{{item.card_name}}
</li>
</ul>
<span ng-click="$parent.selectedIndex=$index">Add </span>
<md-card class="card" ng-show="$parent.selectedIndex == $index" >
<form name="colorForm" class="addcontdrag" >
<md-input-container>
<label>Add text</label>
</md-input-container>
<span>
<md-button class="md-raised md-primary">Save</md-button>
<i class="material-icons" ng-click="$parent.selectedIndex=$index">clear</i>
</span>
</form>
</md-card>
In this code i want to hide the md-card when i click the close button. Show the md-card by using $parent.selectedIndex=$index. But i dont know how to hide the md-card using this one.
If anyone know please help me.
Thanks Advanced...
You will have to place your md-card inside li tag to get the $index.
<ul dnd-list="list" ng-controller="Modalcontrol">
<li ng-repeat="item in list" ng-click="showAdvanced($event)">
{{item.card_name}}
<span ng-click="$parent.selectedIndex=$index">Add </span>
<md-card class="card" ng-show="$parent.selectedIndex == $index" >
<form name="colorForm" class="addcontdrag" >
<md-input-container>
<label>Add text</label>
</md-input-container>
<span>
<md-button class="md-raised md-primary">Save</md-button>
<i class="material-icons" ng-click="$parent.selectedIndex=$index">clear</i>
</span>
</form>
</md-card>
</li>
</ul>

How do I make one button as default in angular?

I have some group of buttons in angular material code, so I want to make the first button as default, where it shows the content of that button on right side.
I have written some code like below, it shows the result after I clicked the button.
<div layout="row" layout-align="space-between">
<div class="list" style="width:30%;height:50px">
<div layout="column" ng-repeat="lists in vm.result | filter:searchText">
<div layout="row" layout-align="space-around">
<md-button class="md-raised" ng-click="vm.showItems(lists._id)">{{lists.wName}}'s Wish List {{$index}}</md-button>
<a style="margin-top:14px; cursor:pointer">{{lists.wType}}</a>
</div>
</div>
</div>
<div class="listItems" style="width:68%;height:400px;">
<div flex-xs flex-gt-xs="30" layout="row" ng-show="vm.showOnClick">
<md-card ng-repeat="product in vm.result" flex="30" style="max-width: 50%;">
<md-card-title>
<md-card-title-text>
<span class="md-subhead">{{product.Product_Name}}</span>
</md-card-title-text>
</md-card-title>
<md-card-title-media style="margin-left: -80px;">
<img ng-src="{{ product.Image }}" class="md-card-image" alt="Image here">
</md-card-title-media>
<md-card-title-text>
<span><span class="md-subhead" style="font-weight: bold; padding:2px;">Price: </span> {{ product.Price }}</span><br/>
<span><span class="md-subhead" style="font-weight: bold; padding:2px;">Brand:</span> {{ product.Brand }}</span><br/>
<span><span class="md-subhead" style="font-weight: bold; padding:2px;">Category: </span> {{ product.Category }}</span><br/>
</md-card-title-text>
</md-card>
</div>
</div>
What you are trying to achieve is to have the first item selected as default when your page is displayed. To do this, your controller should run the showItems method for the first item in the list once they have loaded.
I don't know what your controller or service looks like, but it would be something like (in your controller)
itemsService.loadItems().then(function(items) {
showItems(items[0]);
});

AngularJS ng-hide ng-show or ng-if based on active state of array items

hi so i am building a shopping cart and it has 3 views menu,options,and order. The list is built using ng-repeat from json data. each item in the array as an active field set to false. when an item is added to the order its value is set to true. what i would like to do is when no products in the array are active i would like to hide the option markup and show a "please add items markup" same with the order page.. but my questions is how do i go about and check the entire array and using that boolean to display the view or the "add items markup"
here is my factory function
OrderFactory.checkActive = function(item){
angular.forEach(item, function(item){
if (item.active){
$scope.show = false;
} else {
$scope.show = true;
}
});
}
here is what i'm trying to show/hide
<md-card ng-show="!show">
<md-card-content>
<h1>Please add items</h1>
</md-card-content>
<md-card>
<md-card ng-show="show">
<md-card-content>
<h3 class="md-subhead" align="center">Review And Submit Order</h3>
<md-divider></md-divider>
<md-list ng-repeat="item in menu | filter:true">
<md-list-item layout="row">
<h3>{{ item.name }} Qty:{{item.qty}}</h3>
<span flex></span>
<h3>{{ item.price | currency }}</h3>
</md-list-item>
<md-list-item layout="row" ng-repeat="size in item.sizes | filter:true">
<span>{{ size.name }}</span>
<span flex></span>
<span>{{ size.price | currency }}</span>
</md-list-item>
<md-list-item layout="row" ng-repeat="flavor in item.flavors | filter:true">
<span>{{ flavor.name }}</span>
<span flex></span>
<span>{{ flavor.price | currency }}</span>
</md-list-item>
</md-list>
<md-divider></md-divider>
<md-list>
<md-list-item layout="row">
<h3 class="md-subhead">Order Total:</h3>
<span flex></span>
<h3>{{ total(menu) | currency }}</h3>
</md-list-item>
</md-list>
</md-card-content>
</md-card>
any ideas? thanks for looking
I'd prefer to do it on HTML itself using filter.
Yourng-if/ng-show condition would be ng-if="(menu | filter : {active: true}).length == 0"
Markup
<md-card ng-if="(menu | filter : {active: true}).length == 0">
<md-card-content>
<h1>Please add items</h1>
</md-card-content>
<md-card>
<md-card ng-if="(menu | filter : {active: true}).length > 0">
<md-card-content>
..content here
</md-card-content>
</md-card>
Your foreach code keeps overwriting the value stored in $scope.show. It will only remember the final iteration. Since your are looking for if there are any active items, you should return as soon as you find an active item.
Using your foreach:
OrderFactory.checkActive = function(item){
$scope.show = true; //default to true
angular.forEach(item, function(item){
if (item.active){ //only change value if found an active item
$scope.show = false;
break;
}
});
}
Alternatively, you can use Array.some(predicate) to see if there are any active items.
$scope.show = !itemArray.some(function(item) {
return item.active;
});

Resources