object not responding to Underscore shuffle - backbone.js

I'm working on a backbone project with underscore (1.3.0). Underscore has a shuffle method that shuffles
create a collection
countries = new Countries
child
check length
countries.length
0
fetch the data (using an underscore method, fetch)
countries.fetch();
Object
XHR finished loading: "http://localhost:3000/countries". jquery.js:8215
Now it has a length of four
countries.length
4
try to return a randomly shuffled array
countries.shuffle();
TypeError: Object [object Object] has no method 'shuffle'
shuffle otherwise works in my environment
_.shuffle([1, 2, 3, 4, 5, 6]);
[2, 1, 4, 5, 6, 3]
I watched Ryan Bates backbone railscast, and he essentially does the same thing but his works. One difference, though, was when he created his Collection object, it had a different return value
entries = new Raffler.Collections.Entries()
entries #return value
However, when I create a collection, it returns 'child'
countries = new Countries
child
But I don't see that making a difference because I'm still able to call countries.fetch(); which is an underscore method.
Any suggestions?

You might be using an old version of Backbone, or a version of underscore that's not compatible with your version of Backbone.
The first version of Backbone to include the Collection.shuffle method was 0.9.0. The documentation in those days did not specify the minimum version for underscore, but for Backbone 0.9.1 the minimum was > 1.3.1. For the current Backbone release (0.9.9) it's > 1.4.3.
Also, fetch is not an underscore method.

Related

How do deal with nested Arrays/objects in BehaviorSubjects, Observables?

I generally have problems using rxjs with nested Objects or Arrays.
My current use-case is this:
{a: [
{b: 0, c:[{d:1}]},
{b: 1, e:[{f: 'someString'}]}
]
Task: Get and set the Observable or value of a,b,c,d,e,f. I also want to be able to subscribe to each property.
I had this Problem in a similar use-case with an Array of BehaviorSubjects:
Efficiently get Observable of an array BehaviorSubjects
I generally have problems to use the basic functionality of nested arrays/objects in rxjs.
The basic functionality I mean includes:
Array:
getting Element by Index
using for of/in on Arrays
setting an Element by Index
push, pop, shift, slice, splice, ...
Object:
getting Value by Property name
going into the nested tree: object.key1.key2.key3[3].key4 ...
setting Value by Property name
assign
for of/in loops
Generally:
Destructuring: e.g.: let [variable1, variable2] = someObject;
Maybe other stuff I forgot.
I dont know if and which functions are possible for which rxjs Objects and which make sense (for example you should be able to set values in an Observable directly). But coming from a background without rxjs, I have trouble to manage my rxjs Objects properly.
I think reason for this besides my lack of knowledge and understanding is, that
a. The rxjs Objects don't provide the functionality as I'm used to from normal arrays and objects. e.g.:
let variable1 = array[1].property;
//becomes this (see related stack-Question I mentioned earlier)
let variable2 = array.pipe(mergeMap(d=> d[index].pipe(map(d1 => d1[property]));
// -> what happens here? You first need to know what mergeMap,
// map is doing and you have 5 levels of nested inline functions.
b. To implement the those mentioned functionalities I need to go over the .pipe() function and use some function like mergeMap, map, pluck, ... Functions that aren't directly indicating that you can get the Observable of let's say 'e' in my example. Making something like object.a[1].e wierd to implement (at least I don't know how to do that yet)
EDIT:
I also want to note, that I still love the idea of rxjs which works well in angular. I just have problems using it to it's full extend, as I'm a bit new to angular and consequently rxjs.
I thin RX is mainly focus on dealing with async operations. Mutation of array and object we can perfectly use the methods comes natively with javascript if theres no existing operators. or you can create your own operator for mutation/iteration etc.
Will try to answer some of your question on array/objects mutation, they are actually very straight forward.
Array:
getting Element by Index
map(arr=>arr[index])
using for of/in on Arrays
map(arr=>arry.map(item=>....))
setting an Element by Index
tap(arr=>arr[index]=somevalue)
Object:
getting Value by Property name
pluck('name')
going into the nested tree: object.key1.key2.key3[3].key4 ...
pluck('key1','key2')
setting Value by Property name
map(obj=>({a:value,obj...}))
assign
lets say your really want some pick array index method as rxjs operator you can create something like, same as for..in operations.
const pluckIndex=(index)=>source=>source.pipe(map(arr=>arr[index]))
const source = of([2,3])
source.pipe(pluckIndex(1)).subscribe(x => console.log(x));

Why does Range#select produce an Array object?

Consider I have a Range object,
(1..30).class # => Range
Now consider I am trying to find the factors of num,
num = 30
factors = (1..num).select { |n| num % n == 0 }
factors.class # => Array
For Ruby 2.3.1 a Range object does not have #select, but an Array object does. How is calling Range#select producing an Array object?
I believe that I am not fully understanding the Ruby Object Model. My current understanding is that factors.class.eql? Range should return true, not false.
factors.class.eql? Array # => true
The object model in Ruby is simple, single inheritance but with ability to "mixin" modules to add shared behavior. In your case you are using the select method which exists in the module Enumerable. This module is mixed into Array, Hash, and Range. This gives instances of those classes methods such as select. You can read more about enumerable methods here: https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-select
If you think about it, it makes sense that Range#select returns an Array. You're not selecting contiguous values from the range are you? You're selecting arbitrary values from which the block returns true, this makes it impossible to return a range therefore, #select will always return an array even if it's called on a Hash or any other Class that mixes in Enumerable.
Update:
To understand how Enumerable is returning an Array from a Range
To implement any classes that mix in Enumerable you only have to define the #each method on your class. Say you hypothetically re-implemented Range:
class Range
include Enumerable # mixin
def initialize(first, last)
#number_range = first.upto last # this is an array of ints
end
def each(&block) # this methods returns an enumerable
#number_range.each &block
end
end
With the above we can initialize our hypothetical range instance:
#hypo_range = Range.new 1, 10
And call enumerable methods on it:
#hypo_range.any? { |i| i == 5 } # => true
#hypo_range.select &:odd? # => [1,3,5,7,9]
Because you need only implement #each to hook into the Enumerable API, Ruby knows exactly what to do with it no matter what the class of the object is. This is because in your new #each method you are iterating over an array already! Enumerable uses your each method under the hood to implement all the other enumerable methods on top e.g. any?, select, find, etc.
That #each method is where you tell Ruby how to iterate over your collection of objects. Once Ruby knows how to iterate over your objects the results are already an Array.
Rubinius implementation of Range
You can see here that Range is implemented by using while to loop from the first value until it reaches the last value and yielding to the block on each iteration. The block collects the results into an Array and that's how you get the Array out of calling Range#select because select is using that each under the hood.
https://github.com/rubinius/rubinius/blob/master/core/range.rb#L118
Some resources:
https://www.sitepoint.com/guide-ruby-collections-iii-enumerable-enumerator/
https://mauricio.github.io/2015/01/12/implementing-enumerable-in-ruby.html
http://practicingruby.com/articles/building-enumerable-and-enumerator
Check the docs for Range http://ruby-doc.org/core-2.3.1/Range.html
It says included modules Enumerable. And that's where there are implemented map, all?, any?, find, select, inject and many many more methods.

Converting angular-dragdrop to work with firebase $asArray

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.

Unshifting / Adding to Front of Firebase Object Using AngularFire or Vanilla JavaScript

I have an array / object stored on Firebase that I add items to using AngularFire's $add function. $add is the equivalent of using .push on a regular JavaScript array. The value you specify is added to the end of the array.
Is there anyway to add my value to the front of this array / object stored on Firebase? Something that does the same thing as .unshift in vanilla JavaScript?
I would prefer an AngularFire solution, but vanilla JavaScript solutions are fine if there isn't one.
Since the data isn't stored in an array (prior to AngularFire 0.8 due out next week), and objects are unsorted in js, there is technically no concept of front/back. This is achieved in Firebase by sorting your data keys or by using priorities. See ordered data for more on this topic.
In AngularFire, priorities are stored on records as $priority. You can set this value before saving a record to control its sort ordering:
var data = $firebase(ref);
data.$on('loaded', function() {
data['foo'].$priority = 99;
data.$save('foo');
});
To place an item first in the list, you would simply assign it a smaller priority than the other records.

Backbone - How can I slice a collection?

I've got a Backbone Collection. How can I slice the collection, or at least truncate the list to a certain length?
Assuming that you have your collection defined and initialized and that you want to mutate the collection (change it in place) you have to do:
collection.reset(collection.first(n));
of you can use .last(n) to get last N elements.
If you just wanted to get the first n elements without modyfying the collection just do:
var models = collection.first(n);
Here is a list of all the underscore methods you can use directly on your collection.

Resources