AngularJS protractor test in nested ng-repeat - angularjs

I have nested ng-repeat like this. I am the doing protractor test. So I want to access the first index of parent repeater.
<div ng-repeat="pChild in mainParent | orderBy : 'order'" ng-show="checkfor.qm">
<div ng-repeat="cChild in Child ">
<input id="checkbox-01" type="checkbox" class="ng-valid ng-dirty ng-valid-parse ng-touched ng-not-empty">
</div>
</div>
So, I want to select first child of mainParent and inside it, I want to calculate length of Child.
I am new to protractor test. Please help me. Thanks in Advance

I am assuming that you want to calculate the length of cChild of first child of mainParent. You can use below code.
<div ng-repeat="pChild in mainParent| orderBy : 'order'" ng-show="checkfor.qm" ng-init="parentIndex = $index">
<div ng-repeat="cChild in pChild| orderBy:'iseeit__Priority__c' ">
<span ng-if="parentIndex === 0">cChild.length<span>
</div>
</div>
instantiate the parent index with some local variable, and check if it's the first element.
Let me know, if you are looking for something else.

var elm = element(by.repeater("pChild in mainParent").row(0)).all(by.repeater("cChild in Child")).map(function (elm) {
return elm.element(by.css("input#checkbox-01")).getAttribute("class");
}).then(function (links) {
console.log(links.length);
})
links.length have provided the length.

Related

Can ng-model replace Ids?

Is there a way to avoid IDs while creating elements i.e. using ng-model it is easier to validate form fields and other stuff?
<div ng-repeat="x in TestData">
<input type="text" id="nameField-{{$index}}"/>
</div>
The above code will display the number of input boxes equal to the length of the TestData array where every text box will have a unique id "nameField-0", "nameField-1" and so on, using these IDs we can take the textbox values, validate the fields etc.
<div ng-repeat="x in TestData">
<input type="text" ng-model=""/> <!-- what shall be done here to have unique IDs -->
</div>
Although going with IDs is working fine for me but as far as I can understand If I use IDs then that will not be a pure angular way (or IDs cannot be replaced by mg-models), correct me If I am wrong.
You don't need to grab element with id/name/etc. You can use ng-model to bind your values and ng-pattern to validate them.
<div ng-repeat="x in testData">
<ng-form name="tForm">
<input type="text" name="tInput" ng-model="x.name" ng-pattern="/^[A-Z]*$/" />
<span ng-if="tForm.tInput.$error.pattern" style="color:red">Invalid!</span>
</ng-form>
</div>
See this jsbin.
In your controller add this,
$scope.nameField = [];
in ng-reapeat add this,
<div ng-repeat="x in TestData">
<input type="text" ng-model="nameField[$index]"/>
</div>
nameField will be an array with all your values.
<div ng-repeat="x in TestData" ng-init='this["nameField-"+x]'>
<input ng-model='this["nameField-"+x]'/>
</div>
You use ng-init to add new variables to the controller, "this" refer to your scope, and since the scope is an object, since this[bla] == this.bla tou are actually saying, add to my scope a variable name "nameField=" and you add the x value.
after you have created your variable, just use it in the same way in your ng-model.
If you want to show your variable's value in any div/span, just use it via ng-bind:
<div ng-bind='this["nameField-"+x]'></div>

'or', 'and' in ng-model angularjs

I have a list of items, some of them has property value, some has property default. And I need to bind it into the input[text] with ng-repeat.
Array is looks like:
$scope.arr = [
{value:'name'},
{value:'dog'},
{default:'cat'},
{value:'lastName'},
{default:'ring'}
];
And in html:
<div ng-repeat='item in arr'>
<input type='text' ng-model='item.value || item.default'>
</div>
It works, but I have error message in console "[ngModel:nonassign] http://errors.angularjs.org/1.5.8/ngModel/nonassign?p0=item.value%20%7C%7CNaNtem.default&p1=%3Cinput%20type%3D%22text%22%20ng-model%3D%item.value%20%7C%7C%item.default%22%20class%3D%22ng-pristine%20ng-untouched%20ng-valid%22%3E". Because ng-model doesn't work with expression..
Perhaps there is another way to solve it?
Plnkr example
You can do it this way:
<div ng-repeat='item in arr'>
<input type='text' ng-hide='item.default' ng-model='item.value'>
<input type='text' ng-show='item.default' ng-model='item.default'>
</div>
Plunker example.
You can try to create a second array, using only single type of object and bound it to the view.
Then, you can watch for changes and re-assign values to your original array.
It is more a MVVM approach (creating a "viewModel") that intermediate between the controller model and the view.
$scope.valueOrDefault = function (item){
return item.value|| item.default;
}
and HTML
<div ng-repeat='item in arr'>
<input type='text' ng-model='valueOrDefault(item)'>
</div>

Custom directive to populate dynamic select box AngularJS

I've got the following controller that basically calls a http get service and assigns the data to a show_data scope variable
.controller('forms_controller', function($scope, Form) {
Form.get().then(function(data){
$scope.show_data = data;
});
});
The scope.show_data is then pushed to this view ..
<div ng-repeat="(key, value) in show_data | orderBy:'key' " >
<div ng-switch on="value.Type" >
<div ng-switch-when="attributes" >
<div ng-repeat="(key2, value2) in value | orderBy:'key' ">
<div ng-switch-when="Date" >
<label class="item item-input">
<span class="input-label">{{value2.Label}}</span>
<input identifier="{{value2.Identifier}}" type="date">
</label>
</div>
<div ng-switch-when="Select" >
<label class="item item-input item-select">
<div class="input-label">
{{value2.Label}}
</div>
<select codelist="{{value2.CodeList}}" identifier="{{value2.Identifier}}" >
</select>
</label>
</div>
</div>
</div>
</div>
Which basically checks the data based on the input type and spits out the different form elements based on the data. My problem is I am faced with is with the select box... Each select box has an id [codelist in this case] to the ng-options that should be displayed however, I'd first need to make another http get call to fetch this data before populating the ng-options ...
Please also note that there might be more then one select box per form.
I was thinking of using some kind've custom directive to achieve this?
Any help would be highly appreciated :)
Thank You
Your problem is that the server sends you an "incomplete" object. You need to do additional get requests to "complete" your object.
So this is what you should do: in your controller, iterate over your object and do the additional get-requests and store the results in something that you can call in your html with value2.items.
You don't have to wait with setting $scope.show_data untill all the data is fetched. Angular's two-way binding will synchronize the html as soon as the additional info is available.
Something like this should work.
var n = 0;
for (;n < data.length; n += 1) {
var values = data[n].value
var i = 0;
for (;i < values.length; i += 1) {
// GET based on values[i].CodeList
$http.get(...)
.success(function (data2) {
values[i].items = data2
// Retrieveable in HTML as value2.items
});
}
}

AngularJS - dynamic naming using $index in expression

I have a directive in which i create many ng-form's and i name each form based on the $index (from the ng-repeat). My problem is that i want to show an error container (that contains the error message) when the form is invalid but i cant find how to properly reference the form.
Here is my code:
<ng-form name="innerForm{{$index}}">
<label ... ><input name="input" ... />
<div class="error-container" ng-show="'innerForm'+$index.input.$invalid">
// show the error message
</div>
</ng-form>
I want 'innerForm'+$index.input.$invalid to be evaluated as innerForm5.input.$invalid for example.
I have made many attempts but i can't get it to work. What is the correct way to reference my dynamically named form?
please see here : http://jsbin.com/jocane/4/edit
<div ng-controller="firstCtrl">
<div ng-repeat="object in allMyObjects">
<ng-form name="innerForm{{$index}}">
<input type="text" ng-model="object.name" required name="userName">
<div ng-show="{{'innerForm'+$index}}.userName.$invalid">
error
</div>
</form>
</div>
First thing is that, ng-form creates an isolated scope. So if you give a ng-form static name, it will be ok. No need to append $index or anything.
ng-show="innerForm.input.$invalid"
Code snippet to find form controller using element
var elmParent = $(domEle).parents('form, ng-form, [ng-form]');
var formCtrl = null;
var elemCtrl = null;
if (elmParent.length) {
var elm = angular.element(domEle);
formCtrl = elm.scope().$parent[elmParent.attr('name') || elmParent.attr('ng-form')];
}
Hope this will help

Reference the inputs created with ng-repeat in angular based on the number of variable options

The problem I'm facing, as outlined in the code, is that I can't seem to find out how to bind the second checkboxes (created with ng-repeat) to some model which I would then be able to use further down the code (showing/hiding yet another set of options). Also, I managed to show the additional number of inputs based on the count parameter in the $scope.availableOptions by using the $scope.getItterator function, but now I don't see how would I access the values of these checkboxes? I know I have to somehow use the option "ng-model" but am failing to do so, so any help appreciated.
My code is here, but am showing it here too:
html:
<div ng-controller='MyCtrl'>
Show additional options <input type="checkbox" ng-model="additionalOptions">
<div ng-show="additionalOptions">
<ul>
<li ng-repeat="option in availableOptions">
<label class="checkbox" for="opt_{{option.id}}">
<input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" />
{{option.name}}
<ul ng-show="if the upper checkbox is clicked">
<li>
<input type="text" ng-repeat="i in getItterator(option.count)" ng-model="SOME_VALUE_TO_BE_USED_BELOW"/>
Output the value based on what's entered above in the textboxes (SOME_VALUE_TO_BE_USED_BELOW)
</li>
</ul>
</label>
</li>
</ul>
</div>
</div>
and my js:
function MyCtrl($scope) {
$scope.availableOptions = [{"id":"1","name":"easy","count":"2"},{"id":"2","name":"medium","count":"3"},{"id":"3","name":"hard","count":"2"}];
$scope.getItterator=function(n){
var a = new Array();
for(var i=1; i <= n; i++)
a.push(i);
return a;
};
}
Try ng-model="option.checked":
<input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" ng-model="option.checked"/>
And then you can access this property further below like this:
<ul ng-show="option.checked">
DEMO
If you need to also reference the text box inputs. You create a new property (values) on the option. Like this:
{"id":"1","name":"easy","count":"2",values:[]}
Html:
<div ng-repeat="i in getItterator(option.count)">
<input type="text" ng-model="option.values[$index]"/>
{{option.values[$index]}}
</div>
DEMO
Use this:
<input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" ng-model="option.clicked"/>
{{option.name}}
<ul ng-show="option.clicked">
Basically, you are saying that the top checkbox should store its value in a model for each option option.clicked. And then only showing the information based on the scope item.
Updated Fiddle:
http://jsfiddle.net/CkHhJ/26/
UPDATE:
Here is another updated fiddle to answer your questions second part: http://jsfiddle.net/CkHhJ/27/
The difficulties you were having is likely because you are trying to build dynamic input models. Just bear in mind that you need to use an object for the dynamic values (not a plain string, eg: option.answers[$index].value and not just option.answers[$index]. See: AngularJS: Updating an input with a dynamic ng-model blurs on each key press

Resources