Get ng-model in ng-repeat with Protractor - javascript

How can I get the ng-model in ng-repeat with protractor ?
<div ng-repeat="field in master.linker | orderBy:'country.name'">
<div>
<p> {{ field.country_name }} </p>
<input ng-model="field.text">
</div>
</div>
I use this, but without success :
var result = element.all(by.repeater('field in master.linker').column('field.text'));
result.forEach(function(entry) {
console.log(entry);
});
I would like to compare :
result.forEach(function(entry) {
if (entry.country_name === 'en') {
expect(entry.text (from ng-repeat)).to.eventually.equal(value)
}
});

The .column() would only work for bindings, not the models.
In your case, use the by.model() locator:
var result = element.all(by.repeater('field in master.linker'));
result.each(function(entry) {
var input = entry.element(by.model("field.text"));
// do smth with the input
});
If you want to get the input values, use map():
var inputValues = result.map(function(entry) {
return entry.element(by.model("field.text")).getAttribute("value");
});
// printing out input values
inputValues.then(function (values) {
console.log(values);
});
Answering additional question from a comment:
I have an array, without other fields from my ng-repeat, how can I compare "if (field.country_name === ""en") { expect(field.text).to.eventually.equal(value)}" ?
Use filter():
var fields = element.all(by.repeater('field in master.linker'));
fields.filter(function (field) {
return field.element(by.binding("field.country_name")).getText().then(function (country) {
return country === "en";
});
}).then(function (filteredFields) {
var input = filteredFields[0].element(by.model("field.text"));
expect(input.getAttribute("value")).to.eventually.equal(value);
});;

Related

Force custom filter to work in repeat

I need to use filter in my loop.
Let's say that we have simple array with names: ['Thomas', 'Brian', 'Joana']. I want to view filtered set of names. It works as expected when I use Angular's filter:
<input ng-model="filterText" />
<span ng-repeat="name in names | filter:filterText">{{name}}</span>
but when I want to use some custom filter method it doesn't work when value of 'filterText' input is changed:
<input ng-model="filterText" />
<span ng-repeat="name in names | filter:filterMethod">{{name}}</span>
In js file:
$scope.filterMethod = function(item) {
if ($scope.textFilter==item || $scope.textFilter==null) {
return true;
}
return false;
}
I want to force filtering action on list of names alway when user change 'filterText' input, but actually this list is changed only if it is filtered by Angular predefined filter. Complete plnkr example: plnkr
Implement the custom filter like this
$scope.filterMethod = function(name) {
return function(item){
if(!name ) return item;
if (name && item.startsWith(name)) {
return item;
}
}
}
and change call the filter in the html like this
<span ng-repeat="name in result = (names | filter:filterMethod(filterText))">
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.names = ['Thomas', 'Brian', 'Joana'];
$scope.filterMethod = function(name) {
return function(item){
if(!name ) return item;
if (name && item.startsWith(name)) {
return item;
}
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<input ng-model="filterText" />
<span ng-repeat="name in result = (names | filter:filterMethod(filterText))">
{{name}}
</span>
</div>
You probably need custom filter:
.filter('customFilter', function() {
return function(items, searchText) {
var filtered = [];
//logic
return filtered;
}
});
<span ng-repeat="name in names | customFilter:text">{{name}}</span>
Change $scope.textFilter to $scope.filterText
$scope.filterMethod = function(item) {
if ($scope.textFilter==item || $scope.textFilter==null) {
return true;
}
return false;
}
Here is a fork to your plunkr
http://plnkr.co/edit/a3uSyez0VFGbZ5ZARcu7?p=preview

Strange behavior when splicing array, javascript

I'm working with list of checkboxes and I have next logic behavior for it:
if all items selected, checkbox "select all" is checked
if one of all selected items has been unchecked, checkbox "select all" is unchecked as well
This logic is clear. Depends of what item is checked I extract its id to an additional array and then using this array for request that to get data.
For pushing everything works fine, but for slicing the logic is strange. So I can slice the array until first item is checked, however I unchecked the first item, pushed and sliced items no more related with checkboxes.
I have reproduced plunker with it, so I appreciate if anybody could help me to find what I'm missing.
$scope.modelClass = {
selectedAll: false
};
$scope.selectAllClass = function (array) {
angular.forEach(array, function (item) {
item.selected = $scope.modelClass.selectedAll;
$scope.param =''
});
};
$scope.checkIfAllClassSelected = function (array) {
$scope.modelClass.selectedAll = array.every(function (item) {
return item.selected == true
});
$scope.checked = array.filter(function (item) {
return item.selected == true
}).length;
angular.forEach(array, function (obj) {
if(obj.selected == true){
requestClass(obj)
}
});
};
var selectedClass = [];
var requestClass = function (obj) {
selectedClass.push(obj);
angular.forEach(selectedClass, function (val) {
if (val.selected != true) {
selectedClass.splice(selectedClass.indexOf(val.id), 1);
}
else {
selectedClass = selectedClass.filter(function (elem, index, self) {
return index == self.indexOf(elem);
})
}
});
$scope.param = _.map(selectedClass, 'id')
};
$scope.classes = [
{"id":4,"name":"Achievement","selected":false},
{"id":13,"name":"Information","selected":false},
{"id":6,"name":"Issue","selected":false},
{"id":5,"name":"Message","selected":false},
{"id":9,"name":"Request","selected":false}
]
The logic looks good for me, not sure what's wrong here. I've took the first solution from this post (it looks like you are using the second one) and slightly modified it for your needs.
$scope.model = {
selectedClass : []
}
$scope.isSelectAll = function(){
$scope.model.selectedClass = [];
if($scope.master){
$scope.master = true;
for(var i=0;i<$scope.classes.length;i++){
$scope.model.selectedClass.push($scope.classes[i].id);
}
}
else{
$scope.master = false;
}
angular.forEach($scope.classes, function (item) {
item.selected = $scope.master;
});
$scope.param = $scope.model.selectedClass
}
$scope.isChecked = function() {
var id = this.item.id;
if(this.item.selected){
$scope.model.selectedClass.push(id);
if($scope.model.selectedClass.length == $scope.classes.length ){$scope.master = true;
}
} else {
$scope.master = false;
var index = $scope.model.selectedClass.indexOf(id);
$scope.model.selectedClass.splice(index, 1);
}
$scope.param = $scope.model.selectedClass
}
$scope.classes = [
{"id":4,"name":"Achievement","selected":false},
{"id":13,"name":"Information","selected":false},
{"id":6,"name":"Issue","selected":false},
{"id":5,"name":"Message","selected":false},
{"id":9,"name":"Request","selected":false}
]
html
<div ng-class="{'selected': master, 'default': !master}">
<div>
<input type="checkbox" ng-model="master" ng-change="isSelectAll()" > Select all
</div>
</div>
<div ng-repeat="item in classes | orderBy : 'id'" ng-class="{'selected': item.selected, 'default': !item.selected}">
<div >
<input type="checkbox" ng-model="item.selected" ng-change="isChecked()">
{{ item.name }}
</div>
</div>
this is fixed plunker

Unable to store appended data into array

Hi here is a jquery function i am working on i have appended a particular div. The div has 2 inputs I am trying to capture the input values in data_to_send array but it only captures one input because the names are not unique.
function() {
$('#si-goal-link-btn').click(function() {
$('#si-goal-links').append('<div class="goal-link si-goal"><label for="iconURL">Icon URL</label><input class="si-goal-link form-control" type="file" name="iconURL"><br><label for="title">Title</label><input type="text" placeholder="Enter title" class="si-goal-link form-control" name="title"><br><hr></div>')
})
$('form #si-btn').click(function(e) {
e.preventDefault()
var self = $(this)
var data_to_send = {}
$('form').find('.si-input').each(function() {
if ( $(this).attr('name') != undefined) {
if ($(this).hasClass('si-wysiwyg')){
data_to_send[$(this).attr('name')] = $(this).code()
}
if ($(this).hasClass('si-goal-link')) {
//UNABLE TO STORE THE VALUE HERE
data_to_send[$(this).attr('name')] = $(this).val()
}
data_to_send[$(this).attr('name')] = $(this).val()
}
})
var url = $('form').data('si-location')
$.post(url, data_to_send, function(data) {
})
})
}
How do i capture this data and store it as an array within an array over here ?
To get array-within-array-like behavior in Javascript, you will need to make an array a property of your data object, and then push() the same named values onto that array.
var data_to_send = {};
data_to_send.si-goal-link = [];
//inside loop or wherever is needed
data_to_send.si-goal-link.push($(this).val());
$.post(url, $('form').serialize(), function(data) {
})

How to get all data-* attributes by Prefix

I have a tag like this:
Link
When I click this link, I have a function like this
$('#ssd').click(function (event) {
var customData;
// Code to get all the custom data in format like data-info*
});
Note, the data-info* like attributes could be any number, that means you could see 1 one of them, named data-info1, or there of them, named data-info1, data-info2, data-info3.
How would I do that, I looked up the JQuery selectors, something like Attribute Starts With Selector [name^="value"] won't work because the variation here is on name...
If I console.log($('#ssd').data()); I will get an object with extra attributes that I don't need, toggle: "popover", bs.popover: Popover
Any suggestions?
This is what I did:
dataFullList = $(this).data();
$.each(dataFullList, function (index, value) {
if (index !== "toggle" && index !== "bs.popover") {
item.name = value.split(":")[0];
item.number = value.split(":")[1];
dataIWant.push(item);
}
});
So I will get a dataIWant array without stuff I don't need.
Target all elements which data-* starts with
Custom jQuery selector selector:dataStartsWith()
Here's a custom jQuery selector that will help you to:
Given the data-foo-bar prefix , target the following elements:
data-foo-bar
data-foo-bar-baz
but not:
data-foo-someting
data-something
jQuery.extend(jQuery.expr[':'], {
"dataStartsWith" : function(el, i, p, n) {
var pCamel = p[3].replace(/-([a-z])/ig, function(m,$1) { return $1.toUpperCase(); });
return Object.keys(el.dataset).some(function(i, v){
return i.indexOf(pCamel) > -1;
});
}
});
// Use like:
$('p:dataStartsWith(foo-bar)').css({color:"red"});
// To get a list of data attributes:
$('p:dataStartsWith(foo-bar)').each(function(i, el){
console.log( el.dataset );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p data-foo-bar="a">I have data-foo-bar</p>
<p data-foo-bar-baz="b" data-extra="bbb">I have data-foo-bar-baz</p>
<p data-bar="a">I have data-bar DON'T SELECT ME</p>
<p data-something="b">I have data-something DON'T SELECT ME</p>
Custom jQuery Method $().dataStartsWith()
$.fn.dataStartsWith = function(p) {
var pCamel = p.replace(/-([a-z])/ig, function(m,$1) { return $1.toUpperCase(); });
return this.filter(function(i, el){
return Object.keys(el.dataset).some(function(v){
return v.indexOf(pCamel) > -1;
});
});
};
$('p').dataStartsWith("foo-bar").css({color:"red"});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p data-foo-bar="a">I have data-foo-bar</p>
<p data-foo-bar-baz="b" data-extra="bbb">I have data-foo-bar-baz</p>
<p data-bar="a">I have data-bar DON'T SELECT ME</p>
<p data-something="b">I have data-something DON'T SELECT ME</p>
This function will get the data-info attributes and put them into an array:
function getDataInfo($element, i, a) {
var index = i || 1, array = a || [],
info = $element.data('info' + index);
if(info === undefined) {
return array;
}
array['info' + index] = info;
return getDataInfo($element, index + 1, array);
}
$(function() {
console.log(getDataInfo($('#ssd')));
});
Here's an if condition to isolate the invalid keys while you loop the data. Used as a filter, you can choose to delete the keys you do not want - like this:
$('#ssd').click(function(e){
var data = $(this).data();
for(var key in data) {
//here is a condition to use only those data-info items
if(data.hasOwnProperty(key) && key.indexOf('info') === -1) {
console.log(key); //just to see which key it is
delete data[key]; //if you need to build a collection of only data-info keys
}
}
});
Alternatively, negate the if condition to include only those keys you want.
You can use Prefix Data. It is jQuery plugin. Return the value at the prefixed data store for the first element in the set of matched elements. Returned value can be an object based on the attribute values and attributes name structure.
Usage
Take any HTML tag with multi data-* attributes with the same prefix. In the example we focus on myprefix prefix.
<div id="example-tag"
data-myprefix='{"property1": "value1", "property2": {"property21": "value21"}, "property3": "value2"}'
data-myprefix-property2='{"property22": "value22"}'
data-myprefix-property2-property23="value23"
data-myprefix-property3="overwite-value3"
data-myprefix-property4='{"property41": "value41"}'
data-other="We do not read it"></div>
If you want to read data from data-myprefix and every data-myprefix-* attribute you can use .prefixData() with given prefix.
$('#example-tag').prefixData('myprefix');
The previous example returns the object:
{
property1: "value1",
property2: {
property21: "value21",
property22: "value22",
property23: "value23"
},
property3: "overwite-value3",
property4: {
property41: "value41"
}
}

remove value from the list

I have a list of checkboxes. Upon clicking on each of the checkboxes i am adding the value to the hidden variable. But the question is if I want to remove the value from the list upon unchecking the checkbox . How this piece cab be done
here is the hidden form variable
<input name="IDList[]" type="hidden" id="IDList" value="" />
and the jquery
$(".myCheckboxClass").change(function() {
var output = 0;
$(".myCheckboxClass").change(function() {
if ($(this).is(":checked")) {
output += ", " + $(this).val();
} else {
output = $.grep(output, function(value) {
return value != $(this).val();
});
}
$("#IDList").val(output);
});
});
Something like this: (demo) http://jsfiddle.net/wesbos/5N2kb/1/
we use an object called vals to store the info. ADding and removing as we check/uncheck.
var vals = {};
$('input[type=checkbox]').click(function() {
var that = $(this);
if (that.is(':checked')) {
console.log(this.name);
vals[this.name] = "In your Object";
}
else {
delete vals[this.name];
}
console.log(vals);
});
Following your logic, you could do this:
$('#IDList').data('value', []);
$(".myCheckboxClass").change(function() {
var list = $('#IDList').data('value');
if ($(this).is(":checked")) {
list.push($(this).val());
} else {
var indexToRemove = list.indexOf($(this).val());
list.splice(indexToRemove, 1);
}
$('#IDList').val(list);
});
But if you only care about the value of #IDList upon data submission or other actions, you probably want to consider an alternative approach: collating the checked values when you need them.
$('#form').submit(function() {
var list = $('input.myCheckboxClass:checked', this).map(function() {
return $(this).val();
}).get();
$('#IDList').val(list);
});
See both of the above in action: http://jsfiddle.net/william/F6gVg/1/.

Categories

Resources