Cannot getText from list - angularjs

I am trying to getText but forever reason it is coming up empty. The text is a readonly field called theater and then a list of 28 numbers underneath it. I have tried many different ways of obtaining the text, including getAttribute which returns null. I have a scroll down function that scrolls down the page so I can see that it is recognized by the selector as it is scrolling and counting. I'm really lost on this one. I have an array called theaterArray that matches the text line by line, however cannot do this.
the html looks like this:
<td class="capacity" title="Theater" data-style="theater">
<input class="readonly" type="text" data-bind="value: capacityObservables.theater, readonly: $root.editItem() !== $data || enhanced, valueUpdate: 'afterkeydown'" readonly="readonly">
</td>
what I have for my code:
//I have tried using the data-bind but i get an invalid selector error
var theaterStyle = element.all(by.css('[data-style="theater"]'));
theaterStyle.count().then(function(count) {
console.log(count);
j = 0;
for (var i = 0; i < count; i++) {
//scrolls down the list element by element
browser.executeScript("arguments[0].scrollIntoView();", theaterStyle.get(i).getWebElement());
theaterStyle.get(i).getText().then(function(text) {
console.log(text, theaterArray[j], j);
expect(text).toEqual(theaterArray[j++]);
});
}
});

Perhaps text is stuffed in the value attribute. Did you try this,
element.all(by.css('td[title="Theater"]>input')).each(function(element, index) {
element.getAttribute('value').then(function (text) {
console.log(index, text);
expect(theaterArray.includes(text)).toEqual(true);
});
});

Related

Mat-select doesnt display the array content in ngfor

I have an array of countries and i want to display in a mat-select list of options. I am receiving the data like an object format in this.lngCountries so i need to convert to array first.
I think that the array is not complete before the ngfor is loaded. How can I wait for my function to finish? Because my problem is that when the page loads the ngfor my array is still empty.
My code:
private preparePaisOpts() {
let array = this.lngCountries;
this.paisOps = Object.keys(array).map(function(index) {
let count = array[index];
return count;
});
}
HTML:
<th2-mat-select class="form-field-dark" required [form]="usecaseForm"
formControlFieldName="pais"
placeholder="País">
<mat-option *ngFor="let country of paisOps" [value]="country">{{country}}</mat-option>
</th2-mat-select>
Thanks!!! <3
One way is ngIf
<th2-mat-select *ngIf="paisOps && paisOps.length > 0" class="form-field-dark" required [form]="usecaseForm"
formControlFieldName="pais"
placeholder="País">
<mat-option *ngFor="let country of paisOps" [value]="country">{{country}}</mat-option>
</th2-mat-select>
Better is to show a loading spinner instead of the select as example for a better user experience.
You can set a custom variable, too:
loading: boolean = true;
...
private preparePaisOpts() {
let array = this.lngCountries;
this.paisOps = Object.keys(array).map(function(index) {
let count = array[index];
return count;
});
this.loading = false;
}
and HTML
<th2-mat-select *ngIf="!loading" class="form-field-dark" .......
But!
Normally ngFor will be refresh the data if it's array changing. You write not specific error so I don't know what your problem is.

Repeat an item in ng-repeat

I have an array of objects whereby there is a need to allow the user to add an item that is a duplicate of another. It is triggered when they increase the quantity where a property called 'HasPers' is true.
The HTML markup looks like:
<td width="10%"><input type="number" value="{{productdetails.Quantity}}" ng-model="productdetails.Quantity" min="1" ng-change="change(productdetails)" /></td>
and the function is:
$scope.change = function (item) {
if (item.HasPers) {
item.Quantity = 1;
$scope.items.push(item);
}
};
Initially this had a problem in the repeater wherby it knew it was a duplicat object but this was solved by adding 'track by $index' in the repeater
<tr ng-repeat="productdetails in items track by $index">
http://mutablethought.com/2013/04/25/angular-js-ng-repeat-no-longer-allowing-duplicates/
but the item is clearly still associated with the original since when I change some properties on the original one they change on the duplicate one too. I really want to avoid typing out all of the properties again as in
How to add new key in existing array in angular js?
is there any way to create a new item that is identical to the one being passed in but is a different object?
try
$scope.change = function (item) {
if (item.HasPers) {
var copyItem=angular.copy(item);
copyItem.Quantity = 1;
$scope.items.push(copyItem);
}
};
Try by using angular.copy
$scope.change = function (item) {
if (item.HasPers) {
var newItem = angular.copy(item);
newItem.Quantity = 1;
$scope.items.push(newItem);
}
};

AngularJS ng-repeat splicing array not updating DOM correctly

I'm running into an issue when using ng-repeat to create buttons from an array that is populated through a drag/drop system.
Here is a screenshot of the page. You're suppose to use the Numbers and Symbols to create an expression in the dropzone (gray area). In the screen shot I have a pre tag that is displaying the contents of the array. There is only one object in that array but the repeat is still displaying two. Is there something I'm not understanding about how ng-repeat handles itself when its array is updated?
$scope.arr = [];
//gets called when a number or symbol is dropped
$scope.dropItem = function(draggable, dropzone){
if(dropzone) {
var obj = {
name: draggable.name,
fragmentId: draggable.fragmentId,
controlId: draggable.controlId,
id: hal.utils.generateGuid()
};
$scope.arr.push(obj);
$scope.$apply();
}
};
//callback for draggables inside dropzone
$scope.reorderItem = function(draggable, dropzone){
//reorder
if(dropzone){
}
//remove
else {
for(var i = 0; i < $scope.arr.length; i++){
if($scope.arr[i].id == draggable.value){
$scope.arr.splice(i, 1);
$scope.$apply();
}
}
}
};
HTML
<td class="equation-drop-zone" hal-dropzone="PerimeterEquation" max="10">
<pre>{{arr}}</pre>
<button
ng-repeat="button in arr track by button.id"
hal-draggable="{{button.name}}"
value="{{button.id}}"
hal-text
control-id="{{button.controlId}}"
fragment-id="{{button.fragmentId}}"
drop-callback="reorderItem"
></button>
</td>

Clicking an element inside repeater when another element equals specific input with protractor and jasmine

My HTML structure is this:
<li ng-repeat="m in members">
<div class="col-name">{{m.name}}</div>
<div class="col-trash">
<div class="trash-button"></div>
</div>
</li>
What I want to be able to do is using protractor, click on the trash when m.name equals a specific value.
I've tried things like:
element.all(by.repeater('m in members')).count().then(function (number) {
for (var i = 0 ; i < number ; i++) {
var result = element.all(by.repeater('m in members').row(i));
result.get(0).element(by.binding('m.name')).getAttribute('value').then(function (name) {
if (name == 'John') {
result.get(0).element(by.className('trash-button')).click();
};
});
};
});
This seems like it should work, however, it seems like my function does not even run this.
I've also looked into promises and filters though have not been successful with those either. Keep getting errors.
var array = element.all(by.repeater('m in members'));
array.filter(function (guy) {
guy.getText().then(function (text) {
return text == 'John';
})
}).then(function (selected) {
selected.element(by.className('trash-button')).click()
}
All I would like to do is click on the corresponding trash when looking for a specific member list!
Any help would be much appreciated.
EDIT: suggested I use xpath once I find the correct element, which is fine, the problem is I cannot get the filter function's promise to let me use element(by.xpath...)
If I try:
var array = element.all(by.repeater('m in members'));
array.filter(function (guy) {
guy.getText().then(function (text) {
return text == 'John';
})
}).then(function (selected) {
selected.element(by.xpath('following-sibling::div/div')).click()
}
I get the error:
Failed: Object has no method 'element'
Figured it out. Following the Protractor filter guideline in the API reference and using alecxe's xpath recommendation, this code will click on any element you find after filtering it.
element.all(by.className('col-name')).filter(function (member, index) {
return member.getText().then(function (text) {
return member === 'John';
});
}).then( function (elements) {
elements[0].element(by.xpath('following-sibling::div/div/')).click();
});
You can change the xpath to select different stuff incase your HTML does not look like mine.
It looks like you can avoid searching by repeater, and use by.binding directly. Once you found the value you are interested in, get the following sibling and click it:
element.all(by.binding('m.name')).then(function(elements) {
elements.filter(function(guy) {
guy.getText().then(function (text) {
return text == 'John';
})
}).then(function (m) {
m.element(by.xpath('following-sibling::div/div')).click();
});
});
Or, a pure xpath approach could be:
element(by.xpath('//li/div[#class="col-name" and .="John"]/following-sibling::div/div')).click();

Build a list using Bootstrap ui-typeahead

I'm trying to build a tags input field exactly like the one on this site. The user can start typing tags, the ui-typeahead returns a list from which the user selects a single result, adding it to the list of tags already in the input field.
I started by simplifying the problem to a string concatenation, instead of a list. I can't even get that to work. This is where I've got to, but it doesn't concatenate with the existing value of the field, it replaces it:
<input class="form-control" type="text" ng-model="program.Demographs"
typeahead="d for d in program.providers.Demographs"
typeahead-min-length='3' typeahead-items='10'
typeahead-editable="false"
typeahead-on-select="addItem(program.Demographs)">
Here is the function that should concatenate the string:
$scope.addItem = function (item) {
$scope.program.Demographs = $scope.program.Demographs + item;
};
Can anyone offer any hints or advice?
Try this instead of concatenating;
$scope.program.Demographs = [];
$scope.addItem = function (item) {
$scope.program.Demographs = $scope.program.Demographs.push(item);
};
I thought I'd answer this myself after figuring out that it is not possible to add items to the existing selection in the typeahead input field. Instead, you have to add to a different string or array, not the one bound to the typeahead. Here is an example:
$scope.addDemograph = function (item) {
if ($scope.program.Demographs.indexOf(item) == -1) {
$scope.program.Demographs.push(item);
}
$scope.demographs_input = [];
};
<input class="form-control" type="text" placeholder="Demographs"
ng-model="demographs_input"
typeahead="d for d in program.providers.Demographs"
typeahead-on-select="addDemograph(demographs_input)"> // adds input val to list
<ul class="list-inline">
<li ng-repeat="d in program.Demographs"></li> <!--this list is added to automagically-->
</ul>

Resources