Clicking first tr of table with Protractor - angularjs

I have a table of notes that I want to test.
<table class="table" ng-if="!NotesCtrl.loadingNotes && (NotesCtrl.notes | filter: { client : ClientCtrl.client.id }).length">
<tr class="noteTableItem" ng-repeat="note in NotesCtrl.notes | filter: { client : ClientCtrl.client.id } track by note.id" ng-click="NotesCtrl.showNote(note.id)">
<td>{{ note.title }}</td>
<td>{{ note.created | date: 'dd-MM-yyyy - HH:mm' }}</td>
</tr>
</table>
When I write a test to see if there is only 1 row, it passes:
it('should see one note-item', function(){
var notes = element.all(by.css('.noteTableItem'));
expect(notes.count()).toEqual(1);
});
When I then want to click on the first note, to trigger the ng-click, it fails with the message:
it('should click the first item', function(){
var notes = element.all(by.css('.noteTableItem'));
expect(notes.count()).toEqual(1);
notes.first().click();
expect(noteDialog.isDisplayed());
});
Failed: Element <tr class="noteTableItem ng-scope"> could not be scrolled into view
How can I click the first item with Protractor ? (When I work with a list <ul></ul>, it does work...)

Try with xpath:
element(by.xpath("//table/tr/td[0]")).click();
or
$$("table tr td").get(0).click();

Use executeScript method(native javaScript) like below to scroll the object in the view:
var elem= element(locatorCss('Locator definition'));
browser.executeScript("arguments[0].scrollIntoView();", elem.getWebElement()).then(function(){
elem.click().then(function () {
console.log("Object Clicked!!!");
});
});

Related

ServiceNow spUtil

I'm trying to make a slight improvement to an existing widget that our team created, but can't seem to get it to work correctly. We have a widget that does a RowCount of tasks and groups them by state. I want the RowCount to auto update once a task is complete without having the user press the refresh button. I've read some documentation on $rootscope, $broadcast, and $on, but can't seem to get it to work.
Below is snippet of our HTML:
<table class="table table-sm table-responsive">
<tbody>
<tr class="h3">
<td colspan=2>Complete</td>
</tr>
<tr class="h2 bg-success" ng-repeat="x in data.values track by $index">
<td><span class="glyphicon glyphicon-check"></span></td>
<td>{{x.completedCount}}</td>
</tr>
</tbody>
</table>
A snippet of our Server Script:
var values = [];
var _completedCount;
var gsCompleted = new GlideRecordSecure('sn_hr_core_task');
//CLOSED COMPLETE, CLOSED INCOMPLETE,
gsCompleted.addQuery('state', 'IN', '3,4,7');
gsCompleted.addQuery('assigned_to', gs.getUserID());
gsCompleted.addQuery("parent.state", 'NOT IN', '1,800,900');
gsCompleted.query();
if(gsCompleted){
_completedCount = gsCompleted.getRowCount();
}
else{
_completedCount = 0;
}
values.push(
{
completedCount: _completedCount
});
data.values = values;
How do I get this widget to auto update the Completed row count without refreshing the page? I've been playing around with spUtil recordWatch, but cannot get it to work correctly:
function($scope, $sce, spUtil) {
var c = this;
c.data.loading = true;
//After page initially loads re-call server script to load data
c.server.get({
action: 'retrieve_data'
}).then(function(response) {
c.data.loading = false;
console.log('Response');
console.log(response);
c.data.values = response.data.values;
spUtil.recordWatch($scope, 'sn_hr_core_task', "", function(name,data) {
spUtil.update($scope);
})
});
}
Take a look at the widget Simple List, it has an example of one that may help a bit.
You should be able to change your recordWatch to this
var filter = "stateIN3,4,7^parent.stateNOT IN1,800,900^assigned_to=" + window.NOW.user_id;
spUtil.recordWatch($scope, 'sn_hr_core_task', filter);
You generally won't need a callback function unless there is some specific action you're triggering.

Angular js fetch data from multiple table at the same time

This is not a question about something where I am getting stuck. It's a question about good practice and performance. My code is working properly. But I want to know the correct way of doing this task. Maybe I am already right. Just look at the scenario and the code and please suggest me the right way.
Requirement
I have near about 20 tables in the database, when a user logs in and go to the dashboard page I need to show the data from all the tables. It is not required to show all the data so I am fetching 25 rows from each table using Angular $http and displaying in the dashboard page.
Code
My Angular js code is:
$scope.$on('$viewContentLoaded', function (event) {
$scope.loadDashboardQue(event, '/route1/getDashboardData?user_id=123', 'table1');
$scope.loadDashboardQue(event, '/route2/getDashboardData?user_id=123', 'table2');
$scope.loadDashboardQue(event, '/route3/getDashboardData?user_id=123', 'table3');
$scope.loadDashboardQue(event, '/route4/getDashboardData?user_id=123', 'table4');
$scope.loadDashboardQue(event, '/route5/getDashboardData?user_id=123', 'table5');
$scope.loadDashboardQue(event, '/routeN/getDashboardData?user_id=123', 'tableN');
});
Now loadDashboardQue function defination
$scope.loadDashboardQue = function (event, url, tableName) {
$http.get(url)
.success(function (response) {
if (response.status === 'success') {
//Assigning data to HTML table
if (tableName === 'table1') {
$scope.table1Data = response.data;
}
if (tableName === 'table2') {
$scope.table2Data = response.data;
}
if (tableName === 'table3') {
$scope.table3Data = response.data;
}
if (tableName === 'table4') {
$scope.table4Data = response.data;
}
if (tableName === 'table5') {
$scope.table5Data = response.data;
}
if (tableName === 'tableN') {
$scope.tableNData = response.data;
}
} else {
console.log("Something wrong while fetching data from table ", tableName);
}
})
.error(function (error) {
console.log("The error is :", err);
});
});
HTML table
<table style="width:100%">
<tr>
<th>Nme</th>
<th>Id</th>
<th>Contact No</th>
</tr>
<!--Table1 Data-->
<tr ng-repeat="data in table1Data">
<td>{{ data.user_name }}</td>
<td>{{ data.user_id }}</td>
<td>{{ data.mobile }}</td>
</tr>
<!--Table2 Data-->
<tr ng-repeat="data in table2Data">
<td>{{ data.customerName }}</td>
<td>{{ data.customerId }}</td>
<td>{{ data.phone }}</td>
</tr>
<!--Table3 Data-->
<tr ng-repeat="data in table3Data">
<td>{{ data.student_name }}</td>
<td>{{ data.roll_no }}</td>
<td>{{ data.mobile }}</td>
.
.
.
<!--TableN Data-->
<tr ng-repeat="data in tableNData">
<td>{{ data.developer_name }}</td>
<td>{{ data.id }}</td>
<td>{{ data.mobile }}</td>
</tr>
</table>
You can see in each table the column name is different so I am not able to show all the data in a single ng-repeat. So I have written separate ng-repeat for each and every table.
This code is working fine but when the page starts loading it takes more than 7 seconds so this is my worry(performance wise). So please suggest me if any better way is available to achieve this.
Thanks for your valued time.
Merge Requests
Create a new end-point on your API which will get data from all tables and return it in one request. This will definitely save you some time especially if your request are cross-domain.
The following will not speed your application up, but they you asked about best practices so here goes.
Abstract API Calls to a Service
Try to avoid using $http in your controller. The controller should not be concerned with how to get the data, only that it needs to get it and then what to do with it.
Map Results
If you want to use single ng-repeat in your template, map every result (or part of result if you merged all the requests) so the object structure is the same for every table. The following is a simplified example for the table1.
$scope.tableData = [];
result.data.forEach(row => {
$scope.tableData.push({
id: row.user_id,
mobile: row.mobile,
name: user_id
});
});
This way you can loop through all table data using one ng-repeat.
Use $q.all()
This applies only if you cannot merge you requests on the API level. In you example you are calling the function 25-times manually. It would make sense to make a for loop from 1 to 25 and pu each request into an array:
const promises = [];
for (let i = 1; i <= 25; i++) {
promises.push(loadDashboardQue(YOUR_ARGS_HERE));
}
After that you can wait for all of them to resolve and access the results in the response which will by an array in the same order in which you pushed your requests into the promises variable.
$q.all(promises).then(response => {
// response[0] is table1data etc...
});
I hope this help you somehow. Let me know if you have some questions.

Angular JS - Display only the field with the highest value from JSON data

I have a JSON retrieve from database
[{"id":1,"firstname":"Alan Cayetano","numbers":2},{"id":2,"firstname":"Bong Marcos","numbers":0},{"id":3,"firstname":"I Dont Care","numbers":3},{"id":4,"firstname":"toto tata","numbers":0},{"id":5,"firstname":"titi terter","numbers":0},{"id":6,"firstname":"Ian Go","numbers":0}]
this is the result when displayed in table result
firstname lastname numbers
Alan Cayetano 10
Bong Marcos 4
Ian Go 3
What Ever 0
I only want the data with the highest number value
In this case
firstname lastname numbers
Alan Cayetano 10
This data is dynamically fetch from database
My angular.js
<script src="//code.angularjs.org/1.4.8/angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('//');
$interpolateProvider.endSymbol('//');
});
app.controller('customersCtrl',['$scope','$http',function($scope, $http) {
//$http.get("http://localhost:8093/voters/voters_angular")
$http.get("{{ path('vp_president') }}")
.success(function (response) {
$scope.names= JSON.parse(response);
});
}]);
//console.log(names);
</script>
Table
<div ng-app="myApp" ng-controller="customersCtrl">
<table class="table">
//names//
<thead>
<tr>
<th>Firsname</th>
<th>Lastname</th>
<th>NUm</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in names">
<td>//x.firstname//</td>
<td>//x.lastname//</td>
<td>//x.numbers//</td>
</tr>
</tbody>
</table>
</div>
How to achieve this? I am still learning Angular Js
I wonder if Angular's $last filter will work on this
This should work as describe
Link
<tr ng-repeat="x in names| orderBy:'-numbers' | limitTo:1">
<td>//x.id//</td>
<td>//x.firstname//</td>
<td>//x.numbers//</td>
</tr>
It's better to find your max in the controller, not in the view.
function findMax(names) {
var result = null;
for (var i = 0; i < names.length; i++) {
var name = names[i];
if (result == null || name.numbers > result.numbers) {
result = name;
}
}
return result;
}
$scope.name = findMax($scope.names);
And in html
<tr>
<td>{{name.firstname}}</td>
<td>{{name.lastname}}</td>
<td>{{name.numbers}}</td>
</tr>
In AngularJS it's better to pre-sort your data before showing in the view, the ng-repeat creates a watcher for each object it repeat's, in AngularJS the number of watchers is associated with performance if you have many watchers your performance it's worst.
If you don't need the other values to appear, there is no need to create watchers for that values, so it's better to pre-sort the array.
you can do this :
<tr ng-repeat="x in names | orderBy:numbers:reverse | limitTo:1">
You can use:
angular.forEach($scope.names, function (value, key) { //code });
With angular foreach you can read row by row in your $scope.names, and use your logic for get the msx value.
When:
key -> is the position (use an alert(key) to see the info)
value -> is a the row of the json. For get data use value.id, value.firstname, etc.

how to fix ngtable pagination?

I have developed a ngtable with a filter. The pagination on the table does not work anymore though? When I select the show 10 rows on the bottom of the table it still shows 14 rows? How can i fix the pagination/indexing?
This is my table definition:
<table ng-table="tableParams" class="table">
<tr ng-repeat="account in $parent.filtered =(data | filter:search.accountName | filter:search.id)">
<td data-title="'id'">
{{account.account.accountId.id}}
</td>
<td data-title="'name'">
{{account.account.accountName}}
</td>
</tr>
</table>
plunkr:http://plnkr.co/edit/Rqt6px?p=preview
You need to figure pagination function by yourself. You may see ng-table's example in here.
var Api = $resource("/data");
this.tableParams = new NgTableParams({}, {
getData: function(params) {
// ajax request to api
return Api.get(params.url()).$promise.then(function(data) {
params.total(data.inlineCount); // recal. page nav controls
return data.results;
});
}
});
It first load all the data into Api. The params.url() contains current page and page count. It then use these two variable to return part of dataset. So you may need to figure out how to return this part of data.

In angularjs, I have a filtered list of radio buttons and want to select the first?

I have a list of layers which I'm displaying:
<tr ng-repeat="row in layers | filter:isActive | orderBy:row.name">
<td><input type="radio" id="{{ 'layerOption-' + row.key }}" name="layerOptions" ng-checked="row.checked" /></td>
<td>{{ row.name }}</td>
<td></td>
</tr>
I get the list via:
$scope.isActive = function(layer) { return layer.zoned === $scope.showZonedLayers; };
$scope.layers = values.layers.map(function(item, key) { return {
key: key,
name: item,
checked: key === 0 ? true : false,
zoned: item.indexOf("Zones") > 0
} });
This will set the first element in the list set, but this can be filtered out by the filter. How do I set the first unfiltered/visible radio box to checked?
Can this be done via a filter? If not, what's the equivalent in angular to jquery grep?
Wow, I love angular. Found a very easy solution:
ng-checked="{{$first}}"
will take care of it. And I can get rid of the checked property on the array.
UPDATE:
Setting ng-checked=$first doesn't update the bound value, so it's a bit useless as you can't query the selected value back. I rewrote my code to dump the filter and do it in code instead:
$scope.layers = values.layers.map(function(item, key) { return {
key: key,
name: item,
zoned: item.indexOf("Zones") > 0
} }).filter(function(item) { return item.zoned === $scope.showZonedLayers; });
But that means I have to have a ng-change callback on the checkbox that binds to $scope.showZonedLayers. Just wondering if there is a more elegant way?
You should be able to simply use:
ng-checked="$first"

Resources