I'm working into an Angular app that displays some data into a dataGrid as follows.
<p-dataGrid [value]="docs" [paginator]="true" [rows]="8">
<ng-template let-doc pTemplate="item">
<div class="ui-g-12 ui-md-3">
<span>{{doc.title}}</span>
</div>
</ng-template>
</p-dataGrid>
I'm trying to add a button, that when clicked, displays some info regarding the selected doc. I did it as follows:
<p-dataGrid [value]="docs" [paginator]="true" [rows]="8">
<ng-template let-doc pTemplate="item">
<div class="ui-g-12 ui-md-3">
<span>{{doc.title}}</span>
<button (click)="showDialog(doc.id)" pButton type="button" icon="fas fa-info-circle" iconPos="left" label="Details"></button>
<p-dialog id="{{doc.id}}" #{{doc.id}} [(visible)]="display" modal="modal" width="300" [responsive]="true">
<p>{{doc.title}}</p>
</p-dialog>
</div>
</ng-template>
</p-dataGrid>
Into my component, I added a function:
display: boolean = false;
showDialog(id: string) {
alert(id);
this.display = true;
}
The problem is since I'm using the same variable ("display") to control the visibility of all dialogs, browser gets lost about which dialog it should show/hide. In general, it uses the last one.
Since the quantity of elements into the screen is variable, I cannot create display1, display2, displayN variables. So my doubt is, how do I dynamically control the visibility of an element?
I tried something like with no luck:
showDialog(id: string) {
var e = document.getElementById(id);
e.attributes['ng-reflect-visible'].value = true;
}
There's no need to create as many p-dialog elements as docs. Only once should be enough. So if you extract yours p-dialog outside of your p-datagrid, HTML code becomes something like that :
<p-dataGrid [value]="docs" [paginator]="true" [rows]="8">
<ng-template let-doc pTemplate="item">
<div class="ui-g-12 ui-md-3">
<span>{{doc.title}}</span>
<button (click)="showDialog(doc.id)" pButton type="button" icon="fas fa-info-circle" iconPos="left" label="Details"></button>
</div>
</ng-template>
</p-dataGrid>
<p-dialog id="dialog" [(visible)]="display" modal="modal" width="300" [responsive]="true">
<h1>{{selectedDoc.title}}</h1>
Details : {{selectedDoc.details}}
</p-dialog>
where selectedDoc is assigned when you click on a button :
showDialog(id: string) {
this.selectedDoc = this.docs[id-1];
this.display = true;
}
Here is a working Plunker
Related
I have a button group with some buttons, two created with html and others are created with a ng-repeat. I want that on click the button have an active class so I can custom it to show it's activated.
So here is what I do :
<div class="btn-group" role="group" aria-label="Basic example"
ng-init="selectedTab = 'raw'">
<button class="btn"
ng-click="selectView('raw'); selectedTab = 'raw'; console.log(selectedTab);"
ng-class="{'active':selectedTab === 'raw'}">Raw data
</button>
<button class="btn"
ng-click="selectView('summary'); selectedTab = 'summary'; console.log(selectedTab);"
ng-class="{'active':selectedTab === 'summary'}">Summary
</button>
<button class="btn" ng-repeat="(key, value) in views"
ng-click="selectView(key); selectedTab = key; console.log(selectedTab);"
ng-class="{'active':selectedTab === key}">
{{ key }}
</button>
</div>
My problem is that for the two first one all works fine, when I click on the first button the class active is added, and when I click on the second the class is removed from the first one and added to the second one.
The problem is about the buttons generated by the ng-repeat, when I click on them it's add the active class to the button but when I click on another button it's not removing the class, so they can all have the activate class.
What am I doing wrong ?
Remember that ng-repeat creates its own local scope so any variables you reference there that are not defined on the parent scope will be created locally. Although you can put multiple commands in ng-click it is discouraged - it also seems that doing so will not cause a digest cycle for those items inside the ng-repeat.
You can resolve all of this by making selectedTab a property on your controller and having the selectView method set the value of selectedTab. Here's a quick example:
angular.module('app', [])
.controller('ctrl', ($scope) => {
$scope.selectedTab = 'raw';
$scope.views = {
Detail1: 'details',
Detail2: 'details',
Detail3: 'details'
};
$scope.selectView = function(view) {
$scope.selectedTab = view;
}
});
.active {
color: red !important;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="btn-group"
role="group"
aria-label="Basic example">
<button class="btn"
ng-click="selectView('raw')"
ng-class="{'active':selectedTab === 'raw'}">Raw data</button>
<button class="btn"
ng-click="selectView('summary')"
ng-class="{'active':selectedTab === 'summary'}">Summary</button>
<button class="btn"
ng-repeat="(key, value) in views"
ng-click="selectView(key)"
ng-class="{'active':selectedTab === key}">
{{ key }}
</button>
</div>
</div>
New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view, ng-include and ng-if all create new child scopes, so the problem often shows up when these directives are involved.
The assignment selectedTab = key is being done on the child scope created by the ng-repeat directive. The solution is to do the assignment to a property of an object:
<div class="btn-group" role="group" aria-label="Basic example"
ng-init="selected = {tab:'raw'}">
<button class="btn"
ng-click="selectView('raw'); selected.tab = 'raw';"
ng-class="{'active':selected.tab === 'raw'}">Raw data
</button>
<button class="btn"
ng-click="selectView('summary'); selected.tab = 'summary';"
ng-class="{'active':selected.tab === 'summary'}">Summary
</button>
<button class="btn" ng-repeat="(key, value) in views"
ng-click="selectView(key); selected.tab = key;"
ng-class="{'active':selected.tab === key}">
{{ key }}
</button>
</div>
For more information, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
I am new to AngularJS.
I have created <li> to which I used ng-repeat.
<li> contains images and buttons like like, comment and share which is inside <li> and created by ng-repeat.
I have made function which will replace empty like button to filled like button (By changing background image of button).
But problem is this trigger applies to only first like button and other buttons does not change.
How can I fix this?
Code:
HTML:
<html>
<body>
<ul>
<li ng-repeat="media in images"><div class="imgsub">
<label class="usrlabel">Username</label>
<div class="imagedb">
<input type="hidden" value="{{media.id}}">
<img ng-src="{{ media.imgurl }}" alt="Your photos"/>
</div>
<!-- <br><hr width="50%"> -->
<div class="desc">
<p>{{media.alt}}</p>
<input type="button" class="likebutton" id="likeb" ng-click="like(media.id)" ng-dblclick="dislike(media .id)"/>
<input type="button" class="commentbutton"/>
<input type="button" class="sharebutton"/>
</div>
</div> <br>
</li><br><br><br>
</ul>
</body>
</html>
JS:
$scope.like = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-filled.png)";
alert(imgid);
}
$scope.dislike = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-empty.png)";
}
Thanks for help & suggestions :)
The id for each button should be unique but in your case, it's the same for all buttons ('likeb').
You can set the value of the attribute 'id' for each button dynamically by using '$index' and passing '$index' to the functions as follows:
<input type="button" class="likebutton" id="{{$index}}" ng-click="like($index)" ng-dblclick="dislike($index)"/>
Then in your controller, you can use the functions with the passed value.
For example,
$scope.like = function(index)
{
document.
getElementById(index).
style.backgroundImage = "url(src/assets/like-filled.png)";
}
Another good alternative in your case would be to use the directive ngClass.
use 2 css class for styling liked and disliked state, and then put the class conditionally with ng-class instead of DOM handling. and if you really want to perform a DOM operation (I will not recommend) then you can pass $event and style $event.currentTarget in order to perform some operation on that DOM object.
I have a loop ng-repeat that displays sevral icons.
<div class="box">
<div class="box-body">
<div class="row" >
<div class="col-sm-6" style="margin-bottom: 5px;" ng-repeat="record in newlayout.display" align="center">
<a class="btn btn-app" ng-href="#newlayout/{{newlayout.url}}{{newlayout.itemValue}}" >
<span class="badge bg-yellow" style="font-size:22px;">{{record.numberOfSamples}}</span>
<i class="fa fa-{{newlayout.labStyle}}"></i> {{record.lab}}
</a>
</div>
</div>
</div>
</div>
My issue is that the second part of the binded variable itemValue should be dynamic
In my Js, I have this
newLayout.url = 'sublabs/?labName=';
newLayout.itemValue = 'record.lab';
The URL is dynamic.
When I click on the first displayed Icon, the url should look like this :
But it didn't work as I had a compilation error..
Does someone have an idea how to fix this:
http://localhost:8181/#/newlayout/sublabs?labName=PIA/C1 - Shiftlabo
Where the record value "PIA/C1 - Shiftlabo" change.
So basically here if I change
<a class="btn btn-app" ng-href="#newlayout/{{newlayout.url}}{{newlayout.itemValue}}" >
{{newlayout.itemValue}} by {{record.lab}} it would work..but the {{record.**lab**}} should be dynamic as it will have another value when I click on the icon. It will change to {{record.subLab}}
Thanks
Use property acccessor bracket notation inside the binding:
<div>{{record[labOrSublab]}}</div>
JS
var isSublab = false;
$scope.labOrSublab = "lab";
$scope.clickHandler = function() {
isSublab = !isSublab;
$scope.labOrSublab = isSublab ? 'subLab' : 'lab';
};
I have a button:
<button data-ng-click="toggleElement(asset)" class="btn"><span class="text-center">Add To Cart</span></button>
I would like to hide this button when this element will add in a list and show
a disable button with the title "Added to Cart"!!
I tried it :
<table class="table" data-ng-show="elements!=null && elements.length>0">
<tr data-ng-repeat="element in elements">
<td>
<button data-ng-click="toggleElements(element)" ng-disabled="isDisabled" ng-model="isDisabled" class="btn"><span class="text-center">Add To Cart</span></button>
<td> <button data-ng-click="toggleAsset(elements[$index])" data-ng-disabled="added" class="btn">{{added ? 'Added' : 'Add'}}</button>
</td>
</tr>
</table>
in my controller I have this :
$scope.toggleElements= function (element){
.....
$scope.added = true;
}
Somebody can help me...
I think this will work for you:
<button ng-click="toggleElement(asset)" ng-disabled="asset.added">{{asset.added ? 'Added' : 'Add'}}</button>
You'll need to set the property asset.added inside the toggleElement() method.
You can execute several instructions inside one ng-click directive.
Just separate them with ; like a normal javascript expression.
For example:
<button ng-click="doIt(); hide = true" ng-hide="hide">
click me!
</button>
here is one solution.
Have a look to the plunk
<button ng-repeat="a in [0,1,2]" data-ng-click="added = !added" class="btn" ng-disabled="added">
<span ng-show="!added" class="text-center">Add To Cart</span>
<span ng-show="added" class="text-center">Added To Cart</span>
</button>
I'm trying to create a form like below, this using ng-repeat directive in angular and it whenever I created a new row complains
"Duplicates in a repeater are not allowed.".
While I understand the solution for this is by putting "track by $index", however it causes another issue, which clicking delete on one row deletes the value of other field. So I suspect that track by index is OK for static text but not input form. So how to use ng-repeat correctly for my case? See my JSFiddle for demo.
My current code :
HTML
<div class="row-fluid spacer10">
<a ng-click="addAKA()" class="btn btn-primary spacer5 left30"><i class="icon-plus icon-white"></i> Add New Alias</a>
</div>
<div class="row-fluid spacer10"></div>
<div class="row-fluid spacer5" ng-repeat="item in aliasList track by $index">
<input type="text" class="span6 left30" ng-model="item">
<button class="btn btn-danger" ng-click="deleteAKA($index)">delete</button>
<BR/>
</div>
Javascript
$scope.addAKA = function ()
{
if($scope.aliasList == null)
{
$scope.aliasList = [];
}
$scope.aliasList.push("");
$scope.aliasjson = JSON.stringify($scope.aliasList);
}
$scope.deleteAKA = function (idx)
{
var aka_to_delete = $scope.aliasList[idx];
$scope.aliasList.splice(idx, 1);
$scope.aliasjson = JSON.stringify($scope.aliasList);
}
Just change the way you iterate. Instead of this:
<div ng-repeat="item in aliasList track by $index">
do this:
<div ng-repeat="item in aliasList">
$index will be still available inside the element, use like this:
<button ng-click='deleteItem($index)'>Delete</button>
See this JSFiddle for a correct solution
There are multiple problems with your approach.
Since you are directly binding a string to ng-model and ng-repeat creates a child scope, any change to the value would not reflect back. Change you scope model to something like
$scope.list = [{text:"one"},{text:"two"}];
and bind to i.text instead of binding to i as you did earlier.
The deleteItem method was called using item instead of index. See my fiddle here
http://jsfiddle.net/JS6aJ/1/