How can I move a model within a collection? - collections

Say I'm having a plain Backbone.Collection with some models in it:
var Library = Backbone.Collection.extend({
model: Book
});
lib = new Library(
[Book1, Book2, Book3, Book4, Book5, Book6]
]);
How can I move a model within a collection - e.g. the 5th one to the 2nd position? So no sorting by a model field but just changing the sort order manually.
Note: I simplified the models Book1, .... They are of course Backbone.Models.

You can directly access the array of models to modify the order. Loosely based on this question Move an array element from one array position to another, something like this should work:
var c = new Backbone.Collection([{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}]);
console.log(c.pluck("id"));
var from_ix = 4,
to_ix = 1;
c.models.splice(to_ix, 0, c.models.splice(from_ix, 1)[0]);
console.log(c.pluck("id"));
And a demo http://jsfiddle.net/nikoshr/5DGJs/

Related

How to flatten FeatureCollection to a table when reducing Regions

All this gee is new for me.
I'm trying to flatten and export a table resulting from reduceRegions. The resulting json is a FeatureCollection but trying to .flatten() will thrown an error.
// Import WDPA dataset
var dataset = ee.FeatureCollection('WCMC/WDPA/current/polygons');
//var roi = dataset.filter(ee.Filter.eq('WDPAID', 33046)); // Cacheu
var roi = dataset.filter(ee.Filter.eq('PARENT_ISO', 'GNB')).select('WDPAID'); // all PA in GNB
// Import Global Forest Change dataset.
var dataset = ee.Image('UMD/hansen/global_forest_change_2019_v1_7').clip(roi);
// Subset the loss year layer; make units absolute (instead of years since 2000).
var treeLoss = dataset.select('lossyear').add(2000).selfMask();
// Display year of forest loss detection to the map.
Map.setOptions('SATELLITE');
Map.addLayer(treeLoss, {
min: 2001,
max: 2019,
palette: ['0D0887', '5B02A3', '9A179B', 'CB4678',
'EB7852', 'FBB32F', 'F0F921']
}, 'Tree loss year');
var forestloss = treeLoss.reduceRegions({
'collection': roi,
'reducer': ee.Reducer.frequencyHistogram(),
'scale': 100,
'crs': 'EPSG:5070'})
.select('histogram');
This went well with a single feature in my roi but but when I try to use a featurecollection and add a .flatten() at this point, I get an error
"the input collection must be a collection of collections but the
element ... was feature, which is not a collection."
print(forestloss, 'forestloss');
Map.setOptions('SATELLITE');
Map.centerObject(roi)
Map.addLayer(roi, {}, 'WDPA GB', true);
link to code.
Any help will be much appreciated.
[EDITED] works fine with a single feature but not with a collection of features
.flatten() does only one thing: convert a feature collection of feature collections into a feature collection of those collections. In your case, you have a feature collection (the output of reduceRegions) which contains plain features, but each of those features has a property which is a dictionary.
In order to convert that to multiple features (rows in your exported table), you need to first map over the collection to convert the dictionary to a collection of features, and then flatten the collection.
var forestLossCollection =
treeLoss.reduceRegions({
'collection': roi,
'reducer': ee.Reducer.frequencyHistogram(),
'scale': 100,
'crs': 'EPSG:5070'
})
.map(function (lossInRegionFeature) {
// Get the histogram dictionary from the feature produced by reduceRegions.
var forestLossDict = ee.Dictionary(lossInRegionFeature.get('histogram'));
// Make a FeatureCollection out of the dictionary.
return ee.FeatureCollection(
forestLossDict
.map(function (key, value) {
// Construct a feature from the dictionary entry.
return ee.Feature(null, {
'system:index': key,
'WDPAID': lossInRegionFeature.get('WDPAID'),
'year': key,
'loss': value});
})
// dict.map() returns a dictionary with newly computed values;
// we just want the values in a list, to make a collection of.
.values());
})
// Flatten the collection of collections returned by the map().
.flatten();
print(forestLossCollection);
Export.table.toDrive({
collection: forestLossCollection,
fileNamePrefix: 'forestLoss',
fileFormat: 'csv',
selectors: ['WDPAID', 'year', 'loss'],
});
https://code.earthengine.google.com/2bcfd3d34fed5255e25d5a553558de36

Table Formatting in Google App Maker html template

I have relation data which is in record form:
Record : { Id: 40, Material: test, Size: test, Description: test, Quantity: test, Spec: test, Price:
test, Delivery: test, Quotes_fk: 21},
Record : { Id: 43, Material: test 2, Size: test 2, Description:
test 2, Quantity: test2, Spec: test2, Price: test2, Delivery: test2, Quotes_fk: 21}
I need to present this as a table on a pdf with the headings Id,Material,Size, Description, Quantity, Spec, Price, Delivery and as I am new to coding can’t work it out. I have managed to use Regex format to make it presentable, but it needs to be in table format. So far I can change the data to a string them replace some of the commas with line breaks.
var quotes = questionnaire.QuoteItems;
var quotes2 = quotes.toString();
var quotes3 = quotes2.replace(/{/g , "<br>");
Managed to work through each item in the related record and display using the following code:
for (var i=0; i < questionnaire.QuoteItems.length; i++) {
rows.push([questionnaire.QuoteItems[i].Material, questionnaire.QuoteItems[i].Size, questionnaire.QuoteItems[i].Description, questionnaire.QuoteItems[i].Quantity, questionnaire.QuoteItems[i].Spec, questionnaire.QuoteItems[i].Price, questionnaire.QuoteItems[i].Delivery]);
}

Immutable JS - merge creates a list of map objects from array

I am using redux and immutablejs, and I am trying to create a reducer function.
I have come across some behaviour I did not expect
const a = new Immutable.Map({
numbers: [{id: 1},{id: 2}]
});
const b = a.merge(
{
numbers: [{id: 4},{id: 5}]
}
);
Here are the values of a and b
a.get("numbers");
[Object, Object]
b.get("numbers");
List {size: 2, _origin: 0, _capacity: 2, _level: 5, _root: null…}
b.get("numbers").get(0);
Map {size: 1, _root: ArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false}
I did not expect numbers to be an immutable List of Map objects.
In my application, using redux, I set the initial state to:
const initialState = new Immutable.Map({
error: null,
isBusy: false,
films: []
});
I the reducer, when I fetch films I try to merge them as follows:
return state.merge({
isBusy: false,
films: action.payload,
error: null
});
This causes issues in the react component, as films are initially an array of objects, and then they become an Immutable List of Maps.
Should I create a different initial state, or should I be using a different type of merge? Or something else?
Thanks
I think what you are trying to do is not merge of whole map object, at least should not be in the case you say, it should be update + ( concat or merge ):
const a = new Immutable.Map({
numbers: [{id: 1},{id: 2}]
});
const b = a.update("numbers", numbers =>
numbers.concat([{id: 4},{id: 5}])
// or
numbers.merge([{id: 4},{id: 5}])
);
by doing merge in your code, you are overriding the existing ones due to the nature of "merge" because the keys are the same in the merge; "numbers".

Displaying key-value-pairs out of an array by using a template

I want to display key-value pairs stored in an array (derived from a Session-JSON variable) by using the #each template directive. How can I get access (if possible) to the fields of objects in an array.
Sorry, if this is a question that has been already answered, but I didn't find an appropriate answer here.
Here is some sample code (part of a template helper):
attributes: function () {
var attributes = [];
attributes = [{key: test1, value: 1}, {key: test3, value: 2}, {key: test3, value: 3}];
return attributes;
},
In the template, I used "this" or "this.key". Both didn't work the way as expected.
Thanks for any tipps!
Have you defined variables test1, test3 ? It looks like you put test1 and test3 without ", so it means js is trying to find variables with such names. That's why you couldn't see this.key working.
var attributes = [];
attributes = [{key: "test1", value: 1}, {key: "test2", value: 2}, {key: "test3", value: 3}];
return attributes;
In template:
{{#each attributes}}
{{this.key}} : {{this.value}}<br>
{{/each}}
Output:
test1 : 1<br>
test2 : 2<br>
test3 : 3<br>
Check here

Changes to one variable propagates to another

For example I have two ArrayCollection's - firstAC and secondAC. If I do secondAC = firstAC, and than I make changes to secondAC (prehaps put a filterfunction on it) it somehow propagates to firstAC, would anyone tell me why that happens in Flex or Actionscript 3?
What can I do if I only want secondAC to get all data from firstAC but then when I make changes to secondAC it does not show in firstAC?
Thanxs a bunch for answers!
Ladislav
When you write secondAC = firstAC, you simply state that secondAC and firstAC are references to the same array collection.
What you want is to clone the first collection (as in, copy all elements one by one).
You should be able to do it with something like :
secondAC = new ArrayCollection();
secondAC.addAll(firstAC);
I have no idea of Flex or Actionscript, but looks like firstAC and secondAC point to the same array, therefore that's expected.
What you should do is just create another array, copy members, and they will be two real different entities.
Instead of secondAC = firstAC, you can try secondAC.addAll(firstAC).
In ECMAScript languages (AS1-3, JavaScript, et al.), when you use
var foo = //some value which is not a String or a Number
what you are really saying is "foo now points to the same object as that other variable." This means that in this situation, both arrays will be the same value:
var foo:Array = [ 1, 2, 3 ];
foo = bar;
bar.push( 4 );
trace( foo ); // 1, 2, 3, 4
This also works for functions:
var foo:Array = [ 1, 2, 3 ];
adder( foo );
function adder( bar:Array ):void {
bar.push( 4 );
}
trace( foo ); // 1, 2, 3, 4
and it even works with XML:
var xml:XML = <root><foo/></root>;
var bar:XML = xml;
bar.children()[ 0 ].#bar = 1;
trace( xml.toXMLString() ); // <root><foo bar="1"/></root>
This is called "passing by reference" instead of "passing by value" or "passing by copy". It means that every time that an item is referenced, each variable will point to the same object.
There are many ways to get around this, and most of them depend on your context. For arrays, my favorite is Array.concat(), which returns a literal clone of the array. This means that anything I do to the returned value will not effect the original in any way. If I'm dealing with XML, however, I will do something like: var xml2:XML = XML( xml.toXMLString() );.
In your case, I would actually recommend that you use:
var secondAC:ArrayCollection = new ArrayCollection( firstAC.source.concat() );
This has the major benefits of not only being faster (it relies on compiled code instead of Flex SDK code and it also does not first instantiate a new array and then re-populate it), but it also has the distinct benefit of being available in older versions of Flex 3's SDK -- it is entirely backwards compatible.

Resources