I'm currently trying to figure out if there is a way to do a simple future/past comparison ex.
1) Check state of list by getting list length
2) Perform action which if success increments the list
3) Compare the current list length to the past.
But the concepts of Futures seems to get in my way. One would think this is a pretty normal use case.
Q: How would you go about handling past/future comparisons in Angularjs Scenario?
It's kind of longwinded, but you can define custom matchers which understand futures. For example:
angular.scenario.matcher('toBeGreaterThanFuture', function(future) {
return +this.actual > +future.value;
});
Use like:
listLengthBefore = repeater('.td').count();
// Do some stuff.
listLengthAfter = repeater('.td').count();
expect(listLengthAfter).toBeGreaterThanFuture(listLengthBefore);
Related
I've finally started to understand a lot of info regarding FireStore, but I'm wondering if I can get some assistance.
If I had a setup similar to or like this:
races
Android
name: Android
size: medium
stats <---- this is the map
str: 10
sex: 12.... (more values)
How would I parse this? I am looking to make specific TextViews apply values found in the database so that I can simply update the database and my app will populate those values so that hard coding and code updating won't be nearly as troublesome in the future.
I currently use something like this:
val androidRef = db.collection("races").document("Android")
androidRef.get().addOnSuccessListener { document ->
if (document != null) {
oneOfTheTextViews.text = document.getString("str")
} else {
}
The issue is currently I can only seem to access from collection (races) / document (android) / then a single field (I have "str" set as a single field, not part of a map or array)
What would the best practice be to do this? Should I not nest them at all? And if I can reference said nesting/mapping/array, what functions need to be called? (To be clear, I am not asking only whether or not it is possible - the reference guides and documents allude to such - but what property/class/method/etc needs to be called in order to access only one of those values or point to one of those values?).
Second question: Is there a way to get a list of document names? If I have several races, and simply want to make a spinner or recycler view based on document names as part of a collection, can I read that to the app?
What would the best practice be to do this?
If you want to get the value of your str property which is nested within your stats map, please change the following line of code:
oneOfTheTextViews.text = document.getString("str")
to
oneOfTheTextViews.text = document.getString("stats.str")
If your str property is a number and not a String, then instead of the above line of code please use this one:
oneOfTheTextViews.text = document.getLong("stats.str")
Should I not nest them at all?
No, you can nest as many properties as you want within a Map.
Is there a way to get a list of document names?
Yes, simply iterate the collection and get the document ids using getId() function.
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.
Hi I am looking into Angular 2.0 source code examples in https://angular.io/
I came across this following code. The function "remaining" essentially gets the number of elements in todos array where done is false. It is working fine, I just want to understand what's happening in reduce function. I have basic idea of how reduce function works, but could not understand the syntax here, particularly count+ +!todo.done . I am new to typescript.
export class TodoApp{
todos: Todo[] =[
{text:"learn angular",done:true},
{text:"build angular app",done:false}
];
get remaining(){
return this.todos.reduce((count:number,todo:Todo) => count+ +!todo.done, 0);
}}
If you understand how reduce method works, then you know that the part in callback is supposed to return sum of two values, namely, increment - if task is undone (add 1) or add nothing (zero) if task is done, done equal to true.
This is exactly what this line does
count + +!todo.done
The part +!todo.done is just a confusing type casting and could be rewritten as
count + Number(!Boolean(task.done))
And now it should be clear because toNumber conversion of boolean values follows simple rule (ECMAScript spec): 1 for true, 0 for false.
I want to test if two elements in two different pages are equal. The reason for this is that I need to check a "copy" function that already works in my page, so both elements (divs in this case) have to be indentical:
I found that there's a method in protractor for element objects called "clone" but doesn't explains its purpose that much. Anyway I tried this:
// In the first page:
browser.get("/page1");
var clone1 = element(by.id("firstElem")).clone();
// then navigating to the other page
browser.get("/page2");
var clone2 = element(by.id("secondElem")).clone();
// then the expectation of them to be equal
expect(clone1).toEqual(clone2);
but the expectation fails with a very heavy stacktrace. Also tried comparing:
expect(clone1 == clone2).toBeTruthy();
which fails again.
What is "clone()" supposed to be used for? and,
How do I compare two divs in two separate pages for being identical?
What is "clone()" supposed to be used for?
I've recently created a closely related question, you can follow the updates there:
Cloning element finders
How do I compare two divs in two separate pages for being identical?
Depending on your end goal, you may compare "outer HTML" representations of the elements using getOuterHtml() , example:
browser.get("/page1");
element(by.id("firstElem")).getOuterHtml().then(function(value) {
browser.get("/page2");
expect(element(by.id("secondElem")).getOuterHtml()).toEqual(value);
});
Can you try this:
expect(angular.equals(clone1, clone2).toBe(true));
Read more about angular.equals here: https://docs.angularjs.org/api/ng/function/angular.equals
try without clone
browser.get("/page1");
var clone1 = element(by.id("firstElem"));
browser.get("/page2");
var clone2 = element(by.id("secondElem"));
expect(clone1).toEqual(clone2);
Pretty new to AngularJS and Firebase here, I am trying to convert angular-dragdrop.js as per the following link below to work with angularFire 0.8.0 $asArray feature:
https://github.com/codef0rmer/angular-dragdrop/blob/master/src/angular-dragdrop.js
I was just wondering if the following changes would be sufficient:
1) Include firebase within function declaration
(function (window, angular, firebase, undefined) {
2) Include $firebase within jqyoui callback function
var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$firebase', '$timeout', '$parse', function($timeout, $parse) {
3) Change all the "push" and "splice" update on the dropModelValue and dropModelValue to $add and $remove instead.
dropModelValue.$add(dragItem);
4) Add $save after dropModelValue and dropModelValue assignments
dragModelValue[dragSettings.index] = dropItem;
dragModelValue[dragSettings.index].$save(dragSettings.index);
Your help is much appreciated. Much thanks in advance.
You can utilize $extendFactory to override the push/splice behaviors instead of hacking on the drag drop lib. Ideally, you would just update the priority on the records and let the server move them.
Keep in mind that Firebase data is a JSON object (not an array and therefore not ordered in JavaScript), so moving items in the array has no effect on their position on the server. You must use priorities if you want to enforce an order on the data, other than lexicographical sorting by keys.
Also, you aren't using $save correctly--you call array.$save(item), not item.$save(itemIndex). Judging by these misconceptions, there are likely to be lots of other issues. A trip through the Angular Guide and the Firebase JS Guide be a great primer here.
One technique I have used to reorder a Firebase array using drap & drop, is to rebind the keys to the values so that their lexicographical order match the new order set by the user. Since Firebase will enforce lexicographical order of keys, swapping the keys of 2 values will swap the values. Every time the user drops an item, rebind the keys:
_(myFirebaseArray)
.map('$id')
.sortBy()
// at this stage we have the array of keys sorted lexicographically
// we pair each key with the values, which are sorted by the user
.zipObject(myFirebaseArray)
// for each pair, bind the key to the value and save
.each(function (value, newKey) {
value.$id = newKey
myFirebaseArray.$save(value)
})
This is probably sub-optimal. I was not aware of priorities. This technique can probably be adapted fairly easily to use priorities. The code above should be compatible with lodash from 2 to 4.
Example of this technique in an application here. The ranking array is bound to the drap & dropping through Angular UI.Sortable.