element.remove() method doesn't work sometimes - angularjs

I have a test case that shows that angular element.remove() removes elements from the DOM sometimes, and fails miserably at other times even though I don't see an error. Here is the JSFIDDLE.
To see it working, click the Search button (no need to put in any data in the input field). This does two things:
deletes elements above the field and
deletes any elements below the fields (nothing to delete the first time around) and adds new ones.
This is the code that should clear out the elements below the search button.
$scope.searchTargets.forEach(function(target){
var resultNode = angular.element(document.getElementById('id_' + target.name));
if(resultNode != undefined)
resultNode.remove();
Repeatedly clicking on the search shows that the number of elements below the search button keeps increasing - even though it should really be staying at 3 elements. Why does the remove() method fail here?

Take a look at this forked fiddle:
http://jsfiddle.net/wcca93qc/
You need to reset the search results during each search using $scope.searchResults = [];
I also refactored to code a bit, to merge 3 loops that basically can be done in 1 loop.

Related

How to iterate over elements in selenium

Actually i want to read emails one by one in junk folder of "outlook:live" and mark emails "Not spam".
emails = WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH,"//div[#class = 'xoCOIP8PzdTVy0T6q_uG6']")))
This xpath matches 400 instances. I want to make a loop to select one email at a time like select first email, click on the div and perform action and then 2nd email and so on. I'm trying this
emails = WebDriverWait(driver,
5).until(EC.element_to_be_clickable((By.XPATH,"//div[#class =
'xoCOIP8PzdTVy0T6q_uG6']")))
for count in range(0,len(emails)):
(emails)[count+1].click()
Please help me know where im doing wrong. Thanks in advance
It appears that the function you're using to return the clickable elements is only returning a single element, so you'll have to use a different function, make a change in your logic, etc.
For instance, you could use Selenium's find_elements_by_xpath("//div[#class = 'xoCOIP8PzdTVy0T6q_uG6']") which will return a list of WebElement object(s) if the element(s) are found, or an empty list if the element(s) is not found. This will, of course, not take into consideration the possibility of the elements not being completely loaded on the page. In my experience, just slapping a time.sleep(10) after you open the page is "'good enough".
I recommend making sure your elements can be discovered and interacted with first to make sure this isn't all in vain, if you haven't already.
Another option is to add another function, something like a elements_to_be_clickable() function, to the Expected Conditions source code.
From the Expected Condition documentation, I've done some research and it looks like the element_to_be_clickable() function only returns a single element. Moreover, from the source code, said function mainly makes use of the visibility_of_element_located() function. I believe you could follow similar logic to the element_to_be_clickable() function, but instead use the visibility_of_all_elements_located() function, in order to return multiple WebElements (since visibiilty_of_all_elements_located() returns a list of WebElements).

ngAnimate to detect changes from $http-call with interval

I have an array with a few items in it. Every x seconds, I receive a new array with the latest data. I check if the data has changed, and if it has, I replace the old one with the new one:
if (currentList != responseFromHttpCall) {
currentList = responseFromHttpCall;
}
This messes up the classes provided by ng-animate, as it acts like I replaced all of the items -- well, I do actually, but I don't know how to not.
These changes can occur in the list:
There's one (or more) new item(s) in the list - not necessaryly at the end of the list though.
One (or more) items in the list might be gone (deleted).
One (or more) items might be changed.
Two (or more) items might have been swapped.
Can anyone help me in getting ng-animate to understand what classes to show? I made a small "illustation" of my problem, found here: http://plnkr.co/edit/TS401ra58dgJS18ydsG1?p=preview
Thanks a lot!
To achieve what you want, you will need to modify existing list on controller (vm.list) on every action. I have one solution that may work for your particular example.
you would need to compare 2 lists (loop through first) similar to:
vm.list.forEach((val, index)=>{
// some code to check against array that's coming from ajax call
});
in case of adding you would need to loop against other list (in your case newList):
newList.forEach((val, index)=>{
// some code to check array on controller
});
I'm not saying this is the best solution but it works and will work in your case. Keep in mind - to properly test you will need to click reset after each action since you are looking at same global original list which will persist same data throughout the app cycle since we don't change it - if you want to change it just add before end of each function:
original = angular.copy(vm.list);
You could also make this more generic and put everything on one function, but for example, here's plnkr:
http://plnkr.co/edit/sr5CHji6DbiiknlgFdNm?p=preview
Hope it helps.

$watcher count exploding in ng-repeat virtual scolling

I am trying to implement a virtual scrolling tree directive in Angular using this guide as a reference. However, when I start scrolling, the $watcher count explodes to 17k-20k+ watchers (which crashes the page), scrolling is consistently slow, and nothing I have tried seems to help.
Plunker with my current code: HERE
(Note, above not showing up for me in Firefox, but is working in Chrome). If you have any thoughts of what else I can try so the scrolling is not a disaster, I am open for ideas. Been working on this for way too long...
Other methods I have tried:
$compile(element.components())(scope.$new())
Was called in onScroll(). Result: The list no longer displayed at all/still lagged badly and I got continual "Cannot call method 'insertBefore' of null on $compile" errors until the page crashed.
<li ng-repeat="node in nodeList" vs-node="node"></li>
Aka, I tried to give each element an isolated scope of its own in hopes that its scope and any watchers associated with it would be destroyed when the list was updated. Result was no difference with the watcher issue of above.
function clearVisibleProvider(nodeList){
for(var i=nodeList.length-1; i >= 0; i--){
nodeList[i] = null;
}
return nodeList;
function clearNode(node){
if(node.nodes){
for(var j=node.nodes.length-1; j >= 0; j--){
clearNode(node.nodes[j]);
}
}
nodeList[i] = null;
}
}
An attempt to clear old list elements before replacing them. Again, no difference. It was called within updateDisplayList() before the main list was updated.
Achieved my goal by redesigning to use a regular list view instead. Displayed nodes are flattened into a list, manual indexing is used to keep track of things, and there is no nesting. Any elements that would be nested have padding calculated based on their level of depth in the tree.
There was also a bug where I was getting too many nodes at once as well. Instead of 50, I'd get 200-500. Fixing that did not solve the watch count exploding however, so I don't consider it the source of the original problem.

Expand specific rows in Angular-ui-grid

I'm using angular-ui-grid 3.0.5 with the treeview extension to display a tree. The data loads normally, everything works as expected, except that expandRow fails silently.
My use case is this: suppose we have a path like a > b > c and I need c shown to the user as preselected. I know the selection is correctly done because when I manually expand the parent rows, the child row is indeed selected.
Should I call expandAllRows, all rows would be expanded. However, calling expandRow with references on rows a and b taken from gridOptions.data leads to nothing happening: all rows will remain collapsed.
Is there any precaution to be taken that I have maybe overlooked, or is this a bug?
There's one mention in a closed issue that may be related to this but problem I'm having, but I'm not even sure it's related, given how dry the comment/solution was.
There's no example of using expandRow in the documentation but it's in both the API and the source code.
The gridRow objects mentioned in the documentation http://ui-grid.info/docs/#/api/ui.grid.treeBase.api:PublicApi are not the elements you put into the data array (though this seems to be not explained anywhere).
What the function expects is an object that the grid creates when building the tree, you can access them by looping through the grids treeBase.tree array. This will only be valid when the grid has built the tree, it seems, so it is not directly available when filling in the data, that's why registering a DataChangeCallback helps here https://github.com/angular-ui/ui-grid/issues/3051
// expand the top-level rows
// https://github.com/angular-ui/ui-grid/issues/3051
ctrl.gridApi.grid.registerDataChangeCallback(function() {
if (ctrl.gridApi.grid.treeBase.tree instanceof Array) {
angular.forEach(ctrl.gridApi.grid.treeBase.tree, function(node) {
if (node.row.treeLevel == 0) {
ctrl.gridApi.treeBase.expandRow(node.row);
}
});
}
});
self.onContentReady = function (e) {
e.component.expandRow(e.component.getKeyByRowIndex(0));
e.component.expandRow(e.component.getKeyByRowIndex(1));
};
selec which row you wanna expand

Strange Array behavior using push and splice

I have a page full of mc_card's and want the user to choose which ones to add to their deck.
click a card and cardChosen = true for that card;
click again and cardChosen = false;
This works fine.
Upon choosing a card the frame number is stored in an array. Each card is on a separate frame and there are no duplicates.
Main.cardArray.push(this.currentFrame);
Upon clicking it again, I want to remove that frame number from the array:
Main.cardArray.splice(this.currentFrame, 1);
After I splice the array, I trace it, and I'm getting weird results. Sometimes it works like I would expect, but then it removes the wrong numbers and sometimes doesnt remove them at all.
splice() works in another way, that you try to use.
Here is statement:
splice(startIndex:int, deleteCount:uint, ... values):Array
So, first arg - start index in array to delete, and second arg - how much elements must be deleted from the start index.

Resources