Using href Within ng-repeat - angularjs

I am using AngularFire and Firebase to store objects which contain a title and a url. I call the object list. I want to:
ng-repeat through my array of objects.
Use the list.url to download the URL's contents. All of the URL's are links to either a .js or a .css file.
Apply the download link/function to a button that is nested inside an input-group (Bootstrap 3.3.6).
All of this to be done within a routed view (ui-router)
What the buttons look like within the input-group
Here's my div. It's nested within a routed view. I am working on the first button within input-group-btn.
<div class="list-group">
<a class="list-group-item" ng-repeat="(id, link) in links | filter: search | orderBy: '-downloadCount' | limitTo: 5">
<h4 class="align-left list-group-item-heading">{{ link.name }}</h4>
<h4 class="align-right list-group-item-heading">{{ link.downloadCount }}</h4>
<br>
<br>
<div class="list-group-item-text">
<div class="input-group">
<input type="text" class="form-control" readonly value="{{ link.url }}" />
<div class="input-group-btn">
// *** IT'S THIS FIRST LINK THAT ISN'T WORKING ***
<button class="btn btn-default" ng-href="{{link.url}}"><i class="glyphicon glyphicon-download"></i></button>
<button class="btn btn-primary" ng-click="copyToClipboard(link)" tooltip-placement="bottom" uib-tooltip="Copy"><i class="glyphicon glyphicon-copy"></i></button>
</div>
</div>
</div>
</a>
</div>
When I use anchor tags instead of button tags, the ng-repeat goes crazy, the links get all kinds of messed up, formatting goes haywire, and there ends up being only one copy of the button that doesn't even work.
I'm not sure if I'm supposed to interpolate the link that ng-href is referring to, but I've tried it with and without and I still don't have anything.
Here's my JS to answer a comment.
var ref = new Firebase('https://myApp.firebaseio.com/links');
$scope.links = $firebaseArray(ref);
$scope.addLink = function () {
$scope.links.$add({
name: $scope.newLinkName,
url: $scope.newLinkUrl,
downloadCount: 1
});
$log.info($scope.newLinkName + ' added to database');
$scope.newLinkName = '';
$scope.newLinkUrl = '';
};
$scope.incrementDownloadCount = function (link) {
link.downloadCount += 1;
var tempCount = link.downloadCount;
var currentRef = new Firebase('http://myApp.firebaseio.com/links/' + link.$id);
// update the downloadCount
currentRef.update({ downloadCount: tempCount });
// update priority for sorting
currentRef.setPriority(tempCount);
$log.info(link.name + ' downloadCount changed to ' + link.downloadCount);
};
// Possibly relevant includes
ui.router
ui.bootstrap
firebase

Related

AngularJS- How to handle each button created by ng-repeat

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.

How to bind a part of a variable already binded

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';
};

Protractor Locating elements by by.repeater contained within a specific div

In protractor, I am trying to access the buttons repeated withina specific div with id 'CreateRFQID'. These buttons are defined a directive 'gps-button-bar'. I am trying to access them by.repeater. Because these buttons also appear else where in the page, I can not just access them through
element(by.repeater('aBtn in buttonBarController.config.buttonConfigs track by $index')).
But I am trying without success to get those buttons that are sub element of the div with id 'CreateRFQID'.
Protractor code I am trying:
var parent = element(by.css('#CreateRFQID'));
var first= parent.element(by.repeater('aBtn in buttonBarController.config.buttonConfigs track by $index')).row(0);
first.getText().then(function (text) {
console.log(text);
});
Any help how to get it?
Thanks.
View / html Fragment
<div ng-controller="CreateRFQController as createRFQCntrl" id="CreateRFQID" class="ng-scope">
<gps-button-bar config="createRFQCntrl.buttonBarConfig" class="ng-isolate-scope"><div class="container-fluid">
<div class="row row-buttonBar">
<label><h1 class="panel-title ng-binding">RFQ Create </h1></label>
<span class="pull-right">
<span ng-repeat="aBtn in buttonBarController.config.buttonConfigs track by $index" style="padding-right: 2px" class="ng-scope">
<button class="btn btn-default btn-xs ng-binding" id=""myButton"+$index" ng-click="buttonBarController.clickHandler($index);" data-toggle="tooltip" data-placement="top" title="Create" ng-show="buttonBarController.gpsShownButtons[$index]" ng-disabled="buttonBarController.gpsDisabledButtons[$index]">
<span class="fa fa-floppy-o"></span> Create
</button>
</span><!-- end ngRepeat: aBtn in buttonBarController.config.buttonConfigs track by $index -->
</span>
</div>
You have a problem in the selector, you don't do .row on the result of element but on the by
var parent = element(by.id('CreateRFQID'));
var first = parent.element(by.repeater('aBtn in buttonBarController.config.buttonConfigs track by $index').row(0));
first.getText().then(function (text) {
console.log(text);
});

Append HTML Including ng-repeat directive

I'm trying to append an alert class that includes the angular ng-repeat directive:
ng-repeat="m in orders.messages"
The html appends fine, but the angular does not bind. It simply displays one alert with {{m}} as the contents. When I check Google Developer tools, it includes the directive as well. Also, when I put the static html instead of appending it, it repeats as expected.
var validationErrors = '<div class="alert alert-warning alert-dismissible" role="alert" ng-repeat="m in order.messages"> <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button><strong><span class="glyphicon glyphicon-warning-sign"></span> Warning!</strong> {{ m }} </div>';
$('#errorMessage').append(validationErrors);
Is there a way to append this so that the angular binds?

ng-repeater issue Duplicates in a repeater is not allowed

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/

Resources