I'm working in a collection that contains a model with collections of "itself". For example:
[{
id: 1
name: "John",
children: [
{
id: 32
name: "Peter",
children: []
},
{
id: 54
name: "Mary",
children: [
{
id:12,
name: "Kevin"
}
]
},
]
}]
Let say that I want to get the Kevin "user" by its Id. But all that I have is the "first collection". How can I do that?? And about setting a user within a collection? Another thing: Its possible to get all the Kevin "parents" from him? Like Mary and John?
Does anyone has come to a issue like that?
Thanks a LOT
Well I've made a recursive function on the User's Collection that seems to solved the problem for now ( the best of this is that I can use for retrieve a "deep" model and change it.). Something like that ( if someone has any suggestions, be free to give it a opinion ):
findUserById: function(id) {
var self = new Backbone.Collection(this.toJSON());
return thisCollection(id, this);
function thisCollection(id, collection, array) {
var innerSelf = collection || this;
var thisArray = array || [];
for(var i = innerSelf.models.length; i--;) {
if(innerSelf.models[i].get('id') == id) {
return [innerSelf.models[i]].concat([thisArray]);
}else {
if(innerSelf.models[i].get('children').length > 0) {
thisArray.push(innerSelf.models[i]);
return thisCollection(id, innerSelf.models[i].get('children'), thisArray);
}else {
innerSelf.remove(innerSelf.models[i]);
return thisCollection(id, self, []);
}
}
}
}
}
Basically I return an array with 2 items. The first is the record that I'm looking for and the second is an array with the parents of this user.
Underscore (which is a Backbone dependency, so you already have it) is great for this sort of thing; if you use its "map" function (which Backbone provides as a method on Collection) with its find function, you can do the following:
findPersonInPeopleCollection: function(nameWeAreLookingFor) {
function findChildren(person) {
if (!person.children) return [person];
var children = _.map(person.children, function(child) {
foundPeople.push(findChildren(child);
})
return _.flatten(children);
}
var allPeople = _.flatten(myCollectionOfPeople.map(findChildren));
return _(allPeople).find(function(person) {
return person.get('name') == nameWeAreLookingFor;
}
}
If you wanted to store the parents initially you could either add logic to your "Person" model class's initialize function, eg.
var Person = Backbone.Model.extend({
initialize: function() {
_.each(this.get('children'), function(child) {
child.parent = this;
}, this);
}
});
You could also do something similar by overriding your collection's add method, or adding an event handler to it that triggers after people get added.
Related
I have my json file as below:
{
"components":{
"record1":
[
{
"date":1619038000,
"name":"Susan",
"status":"true"
},
{
"date":1419038000,
"name":"Vinay",
"status":"false"
},
{
"date":1419038000,
"name":"Ajay",
"status":"true"
}
],
"record2":[
{
"date":1419037000,
"name":"Soumya",
"status":"false"
},
{
"date":1619038000,
"name":"Savio",
"status":"true"
},
{
"date":1326439320,
"name":"Thereza",
"status":"false"
}
]
}
}
This is my js file:
var app = angular.module("myApp",[]);
app.controller("Control",function($scope,$http){
$http.get('myData.json').
success(function(data){
$scope.tableData = data.components;
});
});
I want to group data from both arrays and display them in such a way that data having similar dates are grouped together. Maybe if I have more record inside then how wud I do it.Please do help me in this. I want to group them as follows:
date name status 17th april Susan true
Soumya false 19th april Vinay false
Ajay true 20th april Thereza false
I am not sure I understood the question well, but this is how you can gather elements having the same date:
function group(inputs, groupClause) {
var g = {};
for (var key in inputs) {
for (var innerKey in inputs[key]) {
if (inputs[key][innerKey]) {
if (!g[inputs[key][innerKey][groupClause]]) g[inputs[key][innerKey][groupClause]] = [];
g[inputs[key][innerKey][groupClause]].push(inputs[key]);
}
}
}
return g;
}
You can call it like this:
var myGroup = group([myobject["components"]["record1"], myobject["components"]], "date");
If you do not know in advance how many records will be, then you can do something like this:
var input = [];
var index = 1;
while (myobject["components"]["record" + index]) {
input.push(myobject["components"]["record" + index]);
index++;
}
var myGroup = group(input, "date");
Have a look at angular-filter , You add that and you get a bunch of filters which includes groupBy too which can group contents of an array according to the index you specify .
A solution using lodash groupby. Let's say the object is stored in variable called obj. Then you can:
var arr = obj.components.record1.concat(obj.components.record2);
var a = _.groupBy(arr, function(n) {
return n.date;
});
Running this code with the object given in the question, will give something like:
Object { 1326439320: Array[1], 1419037000: Array[1], 1419038000: Array[2], 1619038000: Array[2] }
If you want to loop through one of the groups, just select it bey key:
a["1419038000"].forEach(x => console.log(x))
which will produce:
Object { date: 1419038000, name: "Vinay", status: "false" }
Object {
date: 1419038000, name: "Ajay", status: "true" }
I'm using angular 1.5.9 and I have a JSON object like this:
var data=[
{"id":1,"name":"object 1", childs:[
{"id":51,"name":"object 51", childs:[]},
]},
{"id":2,"name":"object 2", childs:[
{"id":11,"name":"object 11", childs:[]},
{"id":12,"name":"object 12", childs:[
{"id":13,"name":"object 100", childs:[]},
]},
]},
{"id":3,"name":"object 3", childs:[]},
{"id":1,"name":"object 1", childs:[]}
];
I need to filter this tree so that I get all the elements (branches or leaves whose name contains the filter string and all the parents.
i.e: filtering for "100" will result in
[
{"id":2,"name":"object 2", childs:[
{"id":12,"name":"object 12", childs:[
{"id":13,"name":"object 100", childs:[]},
]},
]},
]
This data will then be rendered in a customized tree directive using ng-repeat over the data itself
I'm wondering if someone can suggest a clean and efficent way to achieve this. All the code I've written seems to be too complex and end up traversing the tree so many times that a better way must exist.
actual metacode is somewhat like
* sequenially read ech JSON object in main array
* if name matches add a property (visible:true) and travel back to the beginning setting all the parents' visible:trre
* if childs array contain something, re-call the main filter function to scan all childrens
This could be somewhat acceptable for small datasets, but on large object will probably be very inefficient.
You can just write some recursive javascript for this, something like:
function findObjectAndParents(item, name) {
if (item.name.split(' ')[1] == name) {
return true;
}
for (var i = 0; i < item.childs.length; i++) {
if (findObjectAndParents(item.childs[i], name)) {
return true;
}
}
return false;
}
And use it like this:
var searchName = "100";
var filtered = data.filter(function(item) {
return findObjectAndParents(item, searchName);
});
Ref the answer:
A Javascript function to filter tree structured json with a search term. exclude any object which donot match the search term
function search(array, name) {
const s = (r, { childs, ...object }) => {
if (object.name.includes(name)) {
r.push({ object, childs: [] });
return r;
}
childs = childs.reduce(s, []);
if (childs.length) r.push({ ...object, childs });
return r;
};
return array.reduce(s, []);
}
console.log(JSON.stringify(search(data, '100'),0,2));
Is there any way to search inside nested elements in smart-table? I feed the table with data from a REST Api that consists of the following form:
{
"id": 1,
"small_name": "Foo",
"large_name": "Bar Foo",
"variants": [{"value": "0"}, {"value": "1"}]
}
What I want to achieve is the possibility to filter the data through the value property of the objects inside the variants.
From the Smart Table documentation:
"The stSetFilter replaces the filter used when searching through Smart Table. When the default behavior for stSearch does not meet your demands, like in a select where one entry is a substring of another, use a custom filter to achieve your goals."
http://lorenzofox3.github.io/smart-table-website/
There is also an example available at that site.
I'll post the solution for my problem, maybe it can help someone.
angular.module('YourModule').filter('CustomFilter', [
'$parse',
function ($parse) {
return function(items, filters) {
console.log(items, filters);
var itemsLeft = items.slice();
Object.keys(filters).forEach(function (model) {
var value = filters[model],
getter = $parse(model);
itemsLeft = itemsLeft.filter(function (item) {
if (model === 'value') {
var variants = item.variants.filter(function (variant) {
return getter(variant).match(value);
});
return variants.length;
} else {
return getter(item).match(value);
}
});
});
return itemsLeft;
}
}
])
fiddle: https://jsfiddle.net/ahmadabdul3/L3eeeh6n/
I'm building an app. This app starts with some static data that I can add to, remove from. The problem I'm having (circular dependency) comes from this initial static data. Here's the scenario:
I have 2 services (fruit, basket). Each fruit can belong to only 1 basket, but each basket can hold many fruits. These two services (below) depend on each other:
function fruitService() {}
function basketService() {}
the reason they depend on each other is because of the initial static data that I have:
function fruitService(basketService) {
var data = [
{
id: 0,
name: 'apple',
basket: function() { return basketService.getById(this.refs.basket); },
refs: {
basket: 0
}
}
];
}
as you can see, I have a function basket that returns a basket item, so that I can dynamically retrieve basket objects from fruit objects.
the basket service is similar:
function basketService(fruitService) {
var data = [
{
id: 0,
name: 'basket1',
fruits: function() { return fruitService.getByIdList(this.refs.fruits); },
refs: {
fruits: [0, ...]
}
}
];
}
same as the fruitService, I have a fruits function that can give me fruit objects when I ask for them. I've tried different combinations of ways to try to break apart the actual static data and the service to overcome this circular dependency, but its not happening.
how can I architect this without having this circular dependency
Have one of the services use $injector and do a lookup for the service at runtime
var injectedService = $injector.get('servicenamehere');
You will need to add $injector to your service parameters for this to work (just in case there was any question)
You don't need 2 services. I think that one is enough.
function basketService() {
var data = [
{
id: 0,
name: 'apple',
basketName: 'basket1'
},
];
var service = {
getFruitById: getFruitById,
getBasketById: getBasketById
};
function getFruitById(fruitId){
// return one fruit here
}
function getBasketById(basketId){
// return your basket with a list of fruits
}
}
Another option would be use a constant to store your data.
angular.module('yourApp').Constant("fruitAndBasketConstant", {
baskets : [{
id : 0,
fruits : [
{
// some info
},
{
// some info
}
]
}]
});
And create a service that will query your constant.
angular.module("yourApp").factory("FruitService"["fruitAndBasketConstant", function(fruitAndBasketConstant){
var service = {
getFruitById: getFruitById
};
return service;
function getFruitById(fruitId){
// loop through fruitAndBasketConstant.baskets
// and return the fruit you want
}
}]);
And do the same for your basketService.
I have a local Backbone collection:
var collection = new Backbone.Collection([ { greeting: "hi" }, { greeting: "bye" } ]);
I understand that when I run collection.fetch, Backbone will run collection.set on the results. I need to merge in the response from the server, however. Say the response is:
[ { id: "2", greeting: "hi", name: "Bob" } ]
I would like the resulting collection, after the merge, to be:
[ { id: "2", greeting: "hi", name: "Bob" }, { greeting: "bye" } ]
I understand Backbone already attempts to do some merging here, but if I set the example response above, no merge happens and a new model gets added instead. I assume this is because it merges by id, and here we do not have any ids (in the local collection). In this case, greeting is my unique identifier / key.
The reason I am trying to do this is because I have a local collection and I simply want to see what already exists from that collection (using the key greeting) and merge any findings in.
My solution:
feeds.fetch({
add: false,
remove: false,
merge: false,
data: params,
success: function (feeds, response) {
// Merge any matches
_.each(response.results, function (result) {
_.each(feeds.models, function (feed) {
// We have to `parse` the result before setting it, as Model#set does
// not automatically run `parse` (Collection#set does).
result = feed.parse(result)
if (feed.get('rssUrl') === result.rssUrl) feed.set(result)
})
})
cb(feeds)
}
})
You can tell backbone to use a different key for the id attribute on your model:
GreetingModel = Backbone.Model.extend({
idAttribute: "greeting"
});
GreetingCollection = Backbone.Collection.extend({
model: GreetingModel
});
http://backbonejs.org/#Model-idAttribute
Edit: I suppose you could use two separate collections for local and server side.
var localCollection = new Backbone.Collection([ { greeting: "hi" }, { greeting: "bye" } ]);
ServerCollection = Backbone.Collection.extend({
url: "/api/"
...
});
var serverCollection = new ServerCollection({});
serverCollection.on("reset", function() {
localCollection.each(function(localModel) {
var greeting = localModel.get("greeting");
serverModel = serverCollection.findWhere({greeting: greeting});
if(serverModel) {
localModel.set(serverModel.attributes);
}
});
});
serverCollection.fetch();