So I'm doing e2e test with protractor and angular,
My first test was adding an element to the list,
Now I'm trying to delete it, and I'm having trouble doing so
So this is what I need to do:
Find the name of the record I want to delete
click on the trashcan icon of that same row and delete it
press ok on the pop up window that appears
Try as much as possible to avoid the use of By.css and prefer everything related to angular( byBinding, model, etc) . This is because this part of the app migh eventually change, hence I will have to redo all this cases.
HTML:
...
<div class="list-group-item ng-scope" ng-repeat="item in teamList">
<span class="glyphicon glyphicon-user"></span>
<span ng-bind="item.name" class="memberName ng-binding">nuevo Team</span>
<a ng-click="editTeam(item._id)" class="hand-cursor">
<span class="glyphicon glyphicon-edit memberRemoveBotton"></span>
</a>
<a ng-confirm-click="Would you like to delete this item?" confirmed-click="deleteTeam(item._id)" class="hand-cursor">
<span class="glyphicon glyphicon-trash memberRemoveBotton"></span>
</a>
</div>
JS:
describe('Testing delete Item',function() {
it('Should delete the Item that just got Inserted',function() {
element(by.css('a[href="#!/item-create"]')).click(); //Opens up the Item dashBoard
element.all(by.repeater('item in itemList')).then(function(table) {
table.element(by.binding('item.name')).each(function(names) {
console.log('the names',names.getText());//I'm trying to find the name of the item that just got inserted
// is there like a nested chaining of elements in here ??
});
});
});
});
Any hints on how to solve this are appreciated
describe('Testing delete Item',function() {
it('Should delete the Item that just got Inserted',function() {
// Assume you know the name of the item you want to delete.
var nameToDelete = 'some name';
// Get the row that has the name by using filter.
element.all(by.repeater('item in itemList')).filter(function(row){
return row.element(by.css('.memberName')).getText().then(function(name){
return name === nameToDelete;
});
})
// Now you should have one row.
.get(0)
// Get the row and click find the remove button.
.element(by.css('.memberRemoveBotton'))
.click();
// Make sure it was deleted.
var names = $$('.list-group-item .memberName').getText();
expect(names).not.toContain(nameToDelete);
});
});
Let me know if it works.
Thank's Andres your answer helped me sort out some doubts I was having.
Anyway here is the answer, one of the most tedious part was the popUp window, let's hope it wont brake later on
it('Should delete the Team that just got Inserted',function() {
element(by.css('a[href="#!/team-create"]')).click(); //Opens up the Team dashBoard
element.all(by.repeater('item in teamList')).filter(function(row) {
return row.element(by.css('.memberName')).getText().then(function(name) {
return name === teamName;
});
}).first().element(by.css('.glyphicon-trash')).click();
testHelper.popUpHandler(ptor);
element.all(by.css('.list-group-item .memberName')).each(function(list) {
expect(list.getText()).not.toContain(teamName);
});
});
Related
I'm working on an angular 1.6 based image upload with ng-repeat, note the input is not multi, but there are multiple ng-repeated inputs, I have the image preview working as well as adding lines / removing lines, the only thing that seems to not be working is if I remove an item the file inputs do not update (I have code that does properly update the previews). Here is what I am working with:
<div ng-repeat="item in data.items track by $index">
<input ng-model="item.fileinput" type="file" name="image_{{$index}}" id="image_{{$index}}" onchange="angular.element(this).scope().imageChoose(this)"/><i ng-click="removeEvent($index)" class="fa fa-trash fa-lg"></i>
<img ng-if="!item.thumb" class="preview-image-small" ng-src="/images/general/placeholder.jpg"</img>
<img ng-if="item.thumb" class="preview-image-small" ng-src="{{item.thumb}}"</img>
</div>
Then in my controller I handle the imageChoose as follows:
$scope.imageChoose = function (data) {
var id = data.id.split("_");
id = id[id.length-1];
var elem = document.getElementById(data.id);
if (typeof (FileReader) != "undefined") {
var reader = new FileReader();
reader.onload = function (e) {
$scope.$apply(function() {
$scope.data.data.items[id].thumb = e.target.result;
});
};
reader.readAsDataURL(elem.files[0]);
} else {
alert("This browser does not support FileReader.");
}
};
This properly sets the image previews and when I run a remove on a line they re-order correctly due to the ng-src of event.thumb. The problem is the actual file input does not bind or update, here is the code for removing a line:
$scope.removeEvent = function (index) {
$scope.data.items.splice(index, 1);
};
I'm hoping there is a relatively simple way to bind the input or handle the remove so that the inputs stay correct. Thanks in advance for any ideas.
Your removeEvent method is not working because of using track by $index together with ng-repeat. This is a known side effect. Try removing it/using different track by expressions.
I'm having an issue with ngRepeat :
I want to display a list of students in two different ways. In the first one they are filtered by group, and in the second they are not filtered.
The whole display being quite complex, I use a ngInclude with a template to display each student. I can switch between view by changing bClasseVue, each switch being followed by a $scope.$apply().
<div ng-if="currentCours.classesOfGroup !== undefined"
ng-show="bClassesVue">
<div ng-repeat="group in currentCours.classesOfGroup">
<br>
<h2>Classe : [[group.name]]</h2>
<div class="list-view">
<div class="twelve cell"
ng-repeat="eleve in group.eleves | orderBy:'lastName'"
ng-include="'liste_eleves.html'">
</div>
</div>
</div>
</div>
<div class="list-view" ng-show="!bClassesVue">
<div class="twelve cell"
ng-repeat="eleve in currentCours.eleves.all"
ng-include="'liste_eleves.html'">
</div>
</div>
My problem happens when my list of students change (currentCours here). Instead of refreshing the ngRepeat, both lists concatenate, but only in the unfiltered view.
I tried adding some $scope.$apply in strategic places (and I synchronize my list for example) but it doesn't help.
EDIT : the function used to refresh currentCours in the controller. It's called when a "cours" is selected inside a menu.
$scope.selectCours = function (cours) {
$scope.bClassesVue = false;
$scope.currentCours = cours;
$scope.currentCours.eleves.sync().then(() => {
if ($scope.currentCours.classe.type_groupe === 1) {
let _elevesByGroup = _.groupBy($scope.currentCours.eleves.all, function (oEleve) {
return oEleve.className;
});
$scope.currentCours.classesOfGroup = [];
for(let group in _elevesByGroup) {
$scope.currentCours.classesOfGroup.push({
name: group,
eleves: _elevesByGroup[group]
});
}
$scope.bClassesVue = true;
}
});
utils.safeApply($scope);
};
Well, I found a workaround, but I still don't know why it didn't work, so if someone could write an explanation, I would be very thankful.
My solution was simply to open and close the template each time I switch between views.
So I'm new to angular JS and I am having a problem with editing one object in an array. The liked function below is bring called and the appropriate object is also being passed to it. The loop is even finding the right object and setting its liked value to true. However for some reason when I click the liked button for the second time it still shows the liked value as being false...I'm sure its something super simple.
<div class="thelist" data-ng-repeat="b in data| orderBy:choice">
<h2>{{ b.from }}</h2>
<p>{{b.date}}</p>
<img class="full-image" src="{{b.img}}">
<p>{{b.content}}</p>
<p>{{b.likes}}</p>
<button class="tab-item" ng-click="liked({{b}})"></button>
</div>
App.js:
ref.on("child_added", function (snapshot) {
var newPost = snapshot.val();
$scope.data.push({
content: newPost.content,
date: newPost.date,
from: newPost.from,
img: newPost.img,
likes: newPost.likes,
realdate: newPost.realdate,
id: snapshot.key(),
liked: false
});
});
The liked function:
$scope.liked = function (post) {
if (post.liked == false){
console.log("liked has been run");
angular.forEach($scope.data, function (object) {
if (object.id == post.id) {
object.liked = true;
}
});
//add 1 like on server here
}
}
You must not use templating in ng-click. Change
<button class="tab-item" ng-click="liked({{b}})"></button>
to
<button class="tab-item" ng-click="liked(b)"></button>
To expand on #hege_hegedus's answer, "ng-click" directive takes an expression (javascript expression with access to $scope variables). Since the since it takes an expression and have complete access to $scope, you can think of
<button class="tab-item" ng-click="liked(b)"></button>
as
<button class="tab-item" ng-click="$scope.liked($scope.b)"></button>
I'm using ngRepeat to generate four buttons. Whenever I click one of the buttons, I want to change its color and also execute a function (for now, I'm just using console.log for sake of simplicity). If I click on another button, I want to change its color while reverting the previous button back to its original color.
I have a couple of issues - the first is that I can't seem to get ng-click to accept two commands (the first being the console.log function and the second being the instruction to change the button color). The other issue is that if I take out the console.log function, I end up changing all of the buttons when I click on one.
Any ideas? Here's the plunkr: http://plnkr.co/edit/x1yLEGNOcBNfVw2BhbWA. You'll see the console.log works but the button changing doesn't work. Am I doing something wrong with this ng-click?
<span class="btn cal-btn btn-default" ng-class="{'activeButton':selectedButt === 'me'}" ng-click="log(element);selectedButt = 'me'" data-ng-repeat="element in array">{{element}}</span>
You can create a simple function in your controller which handles this logic:
$scope.selectButton = function(index) {
$scope.activeBtn = index;
}
Then, you can simply check in your template if the current button is active:
<span class="btn cal-btn btn-default" ng-class="{true:'activeButton'}[activeBtn == $index]" ng-click="selectButton($index);" ng-repeat="element in array">{{element}}</span>
I also changed your plunkr
You may convert your element list from string array to object array first.
$scope.array = [
{"name":"first", "checked":false},
{"name":"second", "checked":false},
{"name":"third", "checked":false},
{"name":"fourth", "checked":false}
];
And your log function need to change to:
$scope.log = function(element) {
console.log(element.name);
angular.forEach($scope.array, function(elem) {
elem.checked = false;
});
element.checked = !element.checked;
}
Then, in your HTML:
<button class="btn cal-btn"
ng-repeat="element in array"
ng-click="log(element)"
ng-class="{activeButton: element.checked, 'btn-default': !element.checked}"
>{{element.name}}</button>
Please see the updated plunker here.
How do you get a single item from a GoInstant GoAngular collection? I am trying to create a typical show or edit screen for a single task, but I cannot get any of the task's data to appear.
Here is my AngularJS controller:
.controller('TaskCtrl', function($scope, $stateParams, $goKey) {
$scope.tasks = $goKey('tasks').$sync();
$scope.tasks.$on('ready', function() {
$scope.task = $scope.tasks.$key($stateParams.taskId);
//$scope.task = $scope.tasks.$key('id-146b1c09a84-000-0'); //I tried this too
});
});
And here is the corresponding AngularJS template:
<div class="card">
<ul class="table-view">
<li class="table-view-cell"><h4>{{ task.name }}</h4></li>
</ul>
</div>
Nothing is rendered with {{ task.name }} or by referencing any of the task's properties. Any help will be greatly appreciated.
You might handle these tasks: (a) retrieving a single item from a collection, and (b) responding to a users direction to change application state differently.
Keep in mind, that a GoAngular model (returned by $sync()) is an object, which in the case of a collection of todos might look something like this:
{
"id-146ce1c6c9e-000-0": { "description": "Destroy the Death Start" },
"id-146ce1c6c9e-000-0": { "description": "Defeat the Emperor" }
}
It will of course, have a number of methods too, those can be easily stripped using the $omit method.
If we wanted to retrieve a single item from a collection that had already been synced, we might do it like this (plunkr):
$scope.todos.$sync();
$scope.todos.$on('ready', function() {
var firstKey = (function (obj) {
for (var firstKey in obj) return firstKey;
})($scope.todos.$omit());
$scope.firstTodo = $scope.todos[firstKey].description;
});
In this example, we synchronize the collection, and once it's ready retrieve the key for the first item in the collection, and assign a reference to that item to $scope.firstTodo.
If we are responding to a users input, we'll need the ID to be passed from the view based on a user's interaction, back to the controller. First we'll update our view:
<li ng-repeat="(id, todo) in todos">
{{ todo.description }}
</li>
Now we know which todo the user want's us to modify, we describe that behavior in our controller:
$scope.todos.$sync();
$scope.whichTask = function(todoId) {
console.log('this one:', $scope.todos[todoId]);
// Remove for fun
$scope.todos.$key(todoId).$remove();
}
Here's a working example: plunkr. Hope this helps :)