I'm using Protractor to test an angular page. This page has a table populated by ng-repeat and I would like to extra the text within that table. Here is the HTML code:
<div class="data-group ng-scope" ng-repeat="group in tableData | filter: filterText | orderBy: getValueToOrderByGroup() : sortingCriteria.descending" ng-show="filtered.length > 0">
<div class="data-row group-header">
<div class="col-md-6">
<i ng-click="group.hideRows = !group.hideRows" ng-class="{'rotate-down': group.hideRows}" class="fa fa-fw fa-chevron-right"></i>
<strong class="text-capitalize ng-binding" ng-click="group.hideRows = !group.hideRows"> HEADER TEXT </strong>
</div>
</div>
<div collapse="group.hideRows" class="collapse in" style="height: auto;">
<div class="data-row child-row ng-scope" ng-repeat="thing in filtered = (group.data | filter: filterStuff | filter: filterText | orderBy: getValueToOrderByChild() : sortingCriteria.descending)">
<div class="col-md-3 cell-data child-row-indent text-capitalize">
<span class="clickable-element ng-binding">CHILD ONE</span> <br>
</div>
<div class="col-md-2 child-row-indent-responsive">
<span class="visible-xs visible-sm">Status: </span><span class="ng-binding"> CHILD TWO </span>
</div>
</div>
</div>
And these are my statements to extract the text:
var headerText = element.all(by.repeater('group in tableData')).get(0).all(by.tagName('div')).get(0).element(by.css('div > strong')).getText();
var childOne = element.all(by.repeater('group in tableData')).get(0).all(by.tagName('div')).get(1).element(by.css('div > div:nth-child(1) > span').getText();
When I ran this, it returned a whole block of all the functions but not the actual text. Any help would be appreciated.
It is important to understand that WebdriverJS and protractor itself are entirely based on the concept of promises due to their asynchronous nature. See Promises and the Control Flow.
In other words, getText() in your case returns a promise. If you want to see the actual value, you need to resolve it:
headerText.then(function (text) {
console.log(text);
});
Note that you don't need to resolve promises inside an expect() - it knows how to resolve promises before making an expectation (thanks to jasminewd).
Related
I use the [#ng-select/ng-select][1] component many places in my software. It works well, it searches by a backend method as the user types and shows the results for selection.
Now I would like to let the user to create new items that are not on the list. How can I do this with an async list? productNames is an Observable.
<ng-select [name]="'productname'+index$" [items]="productNames | async"
[attr.id]="'productname'+index$"
[(ngModel)]="detail.productNameNew"
[typeahead]="productNameInput"
(change)="productNameChanged($event, detail)"
(keydown)="productNameKeyPress($event, detail)"
[disabled]="currentSuggestion.acceptUser === null ? null : true"
[clearable]="false">
<ng-template ng-label-tmp let-item="item">
{{item.productName}}
</ng-template>
<ng-template ng-option-tmp let-item="item">
<div class="noproduct-item">
<div class="noproduct-head">
<div class="productname">{{item.productName}}</div>
<div class="description">{{item.description}}</div>
</div>
<div class="noproduct-details">
<div class="headid">
<span class='glyphicon glyphicon-send'></span>
{{item.suggestionHeadId}}
</div>
<div class="createduser">
<span class='glyphicon glyphicon-user'></span>
{{item.createUser?.name}}
</div>
<div class="createddate">
<span class='glyphicon glyphicon-calendar'></span>
{{item.createDate | date: 'yyyy.MM.dd.'}}
</div>
</div>
</div>
</ng-template>
</ng-select>
Add a second observable to capture the user added products and then use combineLatest to merge them. Subscribing to the combined list will produce a new list that you can use in the ng-select.
https://stackblitz.com/edit/angular-rxjs-combinelatest
Below is the html for a table with repeater> div> a> span.
How I can work with filter or Map function to get the compare the second column value i.e idea = ideaOne + ideaTwo + ideaThree + ideaFour along with first column value in loop as this is an anchor tag. Also what would be the proper way to deal with all table values.
Repeater gives me the complete table values but when we use filter & try to click on the first cell value, it's did perform any action neither fail the It block. console value shows all the repeater values are coming in array.
Page Object Class-
getAllTableValues: function () {
return element.all(by.repeater('idea in ctrl.ideaList.ideas')).filter(function(elem) {
return elem.getText().then(function(text) {
return text === 'K';
});
}).click();
},
Spec Class:
tablePage.getAllTableValues().then(function (val) {
console.log("####"+ val);
});
Html Code:
<ul class="total_ideas">
<!----><li ng-repeat="idea in ctrl.ideaList.ideas" class="" style="">
<div class="protractor testing">
<a class="item_idea" ui-sref="xxx.xxx.xxx.xxx.xxx({
'id': idea.id,
'value': idea.name,
'start': (ctrl.dateRange.start | date: 'M-d-y'),
'end': (ctrl.dateRange.end | date: 'M-d-y')
})" href="/xxx/xxx/;value=K">
K
</a>
</div>
<div class="protractor test testing">
<span ng-bind="ctrl.getTotalIdeas(idea)">6</span>
</div>
<div class="protractor test testing">
<span ng-bind="idea.testTerms[ctrl.period].ideaOne">2</span>
</div>
<div class="protractor test testing">
<span ng-bind="idea.testTerms[ctrl.period].ideaTwo">2</span>
</div>
<div class="protractor test testing">
<span ng-bind="idea.testTerms[ctrl.period].ideaThree">2</span>
</div>
<div class="protractor test testing">
<span ng-bind="idea.testTerms[ctrl.period].ideaFour">0</span>
</div>
</li><!----><li ng-repeat="idea in ctrl.ideaList.ideas" class="">
</li><!---->
</ul>
Please suggest here.
I have an array called altSegments, and based on $scope.firstSeg or $scope.lastSeg I'd like to display different parts of that same array. In most cases I change the altSegments array alltogether and it updates fine, but when I go from the same altSegments array to the same array but change the $scope.firstSeg and $scope.lastSeg it doesn't update properly.
I suspect it has something to do with altSegments not having changed and therefore AngularJS deciding that it's not worth it to go over the code again and re-display. How would I get around this?
<li ng-repeat="altseg in altSegments">
<!-- For multiflight home to first -->
<div ng-show="{{firstSeg}}" ng-repeat="flights in altseg.segment_details_1.leg_details">
<p class="small dark">
<strong>Flight:</strong> {{flights.Carrier}} {{ flights.FlightNumber}}
</p>
<p class="small dark">
<strong>Departure:</strong> {{flights.OriginName}} | {{flights.DepartureTime | splitDT }}
</p>
<p class="small dark">
<strong>Arrival:</strong> {{flights.DestinationName}} | {{flights.ArrivalTime | splitDT }}
</p>
</div>
<!-- For multiflight last to home -->
<div ng-show="{{lastSeg}}" ng-repeat="flights in altseg.segment_details_2.leg_details">
<p class="small dark">
<strong>Flight:</strong> {{flights.Carrier}} {{ flights.FlightNumber}}
</p>
<p class="small dark">
<strong>Departure:</strong> {{flights.OriginName}} | {{flights.DepartureTime | splitDT }}
</p>
<p class="small dark">
<strong>Arrival:</strong> {{flights.DestinationName}} | {{flights.ArrivalTime | splitDT }}
</p>
</div>
ng-show is an angular directive and evaluates angular code;
Therefore; you do not need : ng-show="{{firstSeg}}"
Remplace with : ng-show="firstSeg"
See full documentation of ng-show here: https://docs.angularjs.org/api/ng/directive/ngShow
it looks like you are using ng-show="{{firstSeg}}" this should be ng-show="firstSeg" ..
If still doesn't work,
Try to update the data from controller side in $scope.apply() ...
e.g :-
$scope.apply(function(){
list = updated_list; // put your updation of list here
});
I'm trying to create a means to toggle dynamically created rows of information. I've tried using ng-init, and then passing it to a function, but I'm screwing up somewhere and I can't seem to wrap my head around how or if this is possible. The gap, I believe, is in getting the concatenated scope variable to be referenced elsewhere. I'm using Bootstrap 3 and AngularJS 1.5.
The HTML:
<div class="row" data-ng-repeat="equipment in task.equipment">
<div class="col-md-12">
<h4 class="green-text">
{{ equipment.equipId }}
<small class="green-text">
<i class="glyphicon"
data-ng-class="{'glyphicon-triangle-bottom': field{{ $index }}, 'glyphicon-triangle-right': !field{{ $index }}}"
data-ng-init="equipment['field' + $index] = true"
data-ng-click="toggleTaskEquip('field{{ $index }}')">
field{{ $index }}: I WANT THIS TO WORK</i>
</small>
</h4>
</div>
<div data-ng-show="field{{ $index }}">
...stuff here...
</div>
</div>
The JS:
$scope.toggleTaskEquip = function(toggleBool)
{
if (toggleBool === true)
$scope.isTaskEquipOpen = false;
else if (toggleBool === false)
$scope.isTaskEquipOpen = true;
};
If I understand the problem correctly, you want to be able to toggle the boolean created in the ng-init with a click.
I think you need this:
<div class="container-fluid">
<div ng-controller="MyCtrl">
<div class="row" data-ng-repeat="equipment in task.equipment">
<div class="col-md-12">
<h4 class="green-text">
{{equipment.equipId}}
<small class="green-text">
<i class="glyphicon"
data-ng-class="{'glyphicon-triangle-bottom': isVisible, 'glyphicon-triangle-right': !isVisible}"
data-ng-init="isVisible = true"
data-ng-click="isVisible = !isVisible">I WANT THIS TO WORK</i>
</small>
</h4>
</div>
<div data-ng-show="isVisible">
...stuff here...
</div>
</div>
</div>
</div>
You don't even need the function toggleTaskEquip on the $scope.
JSFiddle here.
ng-repeat creates a new scope for each template instance, so you can just create a separate isVisible for each equipment with isVisible = true in the ng-init.
This is my html code :
<h3 ng-repeat="goal in goals" ng-controller="AddGoalsCtrl">
<h4 ng-repeat="(key,value) in goal" ng-controller="AddGoalsCtrl">
{{key}} : {{value}}
</h4>
</h3>
and this is what my service layer returns :
[Goal [goalId=1, goalName=goal1, goalDescription=goaldescript, measurementCriteria=crtr, visible=Y], Goal [goalId=2, goalName=goal1, goalDescription=goal 1 description, measurementCriteria=criteria1, visible=Y], Goal [goalId=3, goalName=goal1, goalDescription=goal 1 description, measurementCriteria=criteria1, visible=Y]]
or json as :
[{"goalId":1,"goalName":"goal1","goalDescription":"goaldescript","measurementCriteria":"crtr","visible":"Y"},{"goalId":2,"goalName":"goal1","goalDescription":"goal 1 description","measurementCriteria":"criteria1","visible":"Y"},{"goalId":3,"goalName":"goal1","goalDescription":"goal 1 description","measurementCriteria":"criteria1","visible":"Y"}]
but my html is not printing anything like key:value .......
you are loading controller many times in a partial.it should not be like that.html code should like this:
<div ng-controller="AddGoalsCtrl">
<h3 ng-repeat="goal in goals" >
<h4 ng-repeat="(key,value) in goal">
{{key}} : {{value}}
</h4>
</h3>
</div>
I created a plunker for you at http://plnkr.co/twdDzpxikJMTe0WuN7ro.
You shouldn't be nesting the controller try something like the following instead:
<body ng-controller="AddGoalsCtrl">
<div ng-repeat="goal in goals">
<h4 ng-repeat="(key,value) in goal">
{{key}} : {{value}}
</h4>
</div>
</body>
Also, don't nest an h tag within another it's not symantically correct HTML. I used a div instead for the outer repeat since you weren't doing anything with it in this example.