Protractor: Finding the right element to test - angularjs

I think I'm misunderstanding how elements works..
HTML code:
<div id="div-item">
A link
<form>
<div>
<select>
<option>1</option>
<option>2</option>
</select>
</div>
</form>
</div>
When I do this:
element(by.tagName('select')).all(by.tagName('option')).count();
This gives me 2, which is correct
When I do this:
element(by.id('div-item')).element(by.tagName('select')).all(by.tagName('option')).count();
This gives me 0. I thought chaining elements finds sub-elements. Is this not correct? How do I restrict the .all(by.tagName('option')) only within this div, rather than the whole page?
This is the xeditable library. My HTML code is:
<div id="div-item" class="col-xs-3">
<a id="xeditable-link" href="#" ng-if="canEdit"
editable-select="user_id"
e-ng-options="user.id as user.name for user in users"
onbeforesave="updateProfile({user_id: $data})">
{{ showNameFromID(user_id) || 'none'}}
</a>
</div>
But this generates a lot of HTML code. It's something like:
<div id="div-item" class="col-xs-3">
<a id="xeditable-link" href="#" ng-if="canEdit"
editable-select="user_id"
e-ng-options="user.id as user.name for user in users"
onbeforesave="updateProfile({user_id: $data})">
{{ showNameFromID(user_id) || 'none'}}
</a>
<form ...>
<div class="xeditable-controle..." ...blah blah>
<select ...ng-options="..." blah blah>
<option>1</option>
<option>2</option>
</select>
<span> ...the buttons... </span>
</div>
</form>
</div>
My test spec:
it('should pass ...', function() {
element(by.id('xeditable-link')).click(); // Click the link to bring up xeditable
element(by.tagName('select')).click(); // Click the select to bring up the popup
var allOptions = element(by.id('div-item')).element(by.tagName('select')).all(by.tagName('option'));
expect(allOptions.count()).toBe(2);
for (var i = 0; i < 2; ++i) {
expect(allOptions.get(i).getText()).toBe(testText[i]);
}
});
Both of the expect statements fail. count is 0, instead of 2 and "NoSuchElementError: No element found using locator: By.tagName("select")"

Try a single css locator
$$('#div-item select [option]').count()
// The same as
element.all(by.css('#div-item select [option]')).count()

Turns out i had a 'div-item' in another .html file. Since AngularJS is a single page application, it was picking up that one instead of the one I wanted.

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

Set Default Value for Multiple Selection Semantic UI Dropdown

I believe there is an answer to my question. I do exactly like some solution I found, but still I can't set default value to my dropdown. Here is my code.
<td>
<div ng-controller="daftarGroup" class="ui fluid multiple selection dropdown">
<input name="group" value="admin" type="hidden">
<i class="dropdown icon"></i>
<div class="default text">Group</div>
<div class="menu">
<div ng-repeat="y in groups" class="item" data-value="{{ y.gid }}">
{{ y.gid }}
</div>
</div>
<script type="text/javascript">
$('.ui.dropdown').dropdown();
</script>
</div>
</td>
My dropdown will have a list of group, one of the item is "admin". The data is presented using Angular. Everytime I load the page, I want the dropdown show "admin" as default value. On another fiddle, it run perfectly, but not in my machine. Every time I refresh the page, no value set on my dropdown, but the list of group is accessible. Any idea about my case?
Thanks.
You can use data-ng-options and ng-init with ng-model to have a default value.
HTML:
<select
ng-init="group = groups[0]"
ng-model="group"
data-ng-options="y.gid for y in groups">
</select>
Angular controller:
$scope.groups = [
{gid: 1},
{gid: 2}
];

changing main content on ng-repeat item click

here is the plunker:
http://plnkr.co/edit/Qj2yxQuT7SZ19u3vuXyq?p=preview
like an inbox.
<div class="col-xs-4 leftnav">
<button class="btn btn-primary btn-block">Add News</button>
<br>
<article ng-repeat="x in issues | filter:query" ng-click="makeActive(i)">
<h4>{{x.title}}</h4>
<p>{{x.message | limitTo:numLimit}}</p>
Read More..
</article>
</div>
<div class="col-xs-8 main-content">
<h2>News</h2>
<hr>
<article ng-repeat="x in issues">
<h3 >{{x.title}}</h3>
<p>{{x.priority}}</p>
<p class="lead">{{x.author}} - 6/12/2014</p>
<!-- ng-if="x.author == 'Andy' " -->
<hr>
<p>{{x.message}}</p>
Read More
<hr>
</article>
</div>
having a list of items ng-repeat on the left, then selecting the main content (on the right) from the options, then displaying the full content as the main selection.
ng-if ? ng-show ?
not sure how well I've described this but it should be pretty obvious from the fiddle.
thanks in advance.
I modified your plnkr http://plnkr.co/edit/9qZsp2o22L5x1a0JofPy?p=preview
I create a currectIssue variable for your right content display.
In left content, Read More.. has been change to <a ng-click="showIssue(x)">Read More..</a>
updated plunk: http://plnkr.co/edit/hGsdkybRMoRct8VykCcB?p=preview
well, you might consider:
- use another scope variable to display the selected item from the object
- I'd use ng-if in this case as that will create/destroy the content as needed
// controller
$scope.selectIssue = function(x) {
$scope.issue = x;
}
$scope.selectIssue($scope.issues['1']);
//view
<article>
<h3 >{{issue.title}}</h3>
<p>{{issue.priority}}</p>
<p class="lead">{{issue.author}} - 6/12/2014</p>
<div ng-if="issue.author == 'Andy'">
<hr>
<p>{{issue.message}}</p>
Read More
<hr>
</div>
</article>

if statement in ng-repeat directive in AngularJS

I have the template:
<div ng-repeat="CableFilterName in CableFilterNames">
<fieldset>
<legend>{{CableFilterName.filterName}}</legend>
<ul id="">
<li ng-repeat="filterValue in CableFilterName.filterValues">
<input type="checkbox"/> {{filterValue}}
<!-- <select> -->
</li>
</ul>
</fieldset>
</div>
where filterValue in nested ng-repeat has several different values. So question is how to define what is current filterValue-value and depending on it use checkbox or select or any arbitrary HTML ?
UPD:
filterValues = ['Cable System','Electrical', 'Lighting'];
To have a kind of if statement, you can use the ngSwitch directive in AngularJS :
http://docs.angularjs.org/api/ng.directive:ngSwitch
For example on your ngRepeat loop :
<div ng-switch on="filterValue">
<div ng-switch-when="value1">//Do what you want when "value1"</div>
<div ng-switch-when="value2">//Do what you want when "value2"</div>
...
<div ng-switch-default>//Do what you want by default</div>
</div>
I Hope it's what you want, I don't really understand what you try to achieve.

Resources