Firebase angular many to many relation query - angularjs

I have a fairly simple json structure of groups and people and I am struggling to get/read a list of the group names for each person from firebase. This is what I tried. I spent a couple of days debugging unsuccessfully. Help much appreciated.
JSON:
{
"groups" : {
"one" : {
"members" : {
"-KLxjv9OnQB2l5Ohr-7I" : true
},
"name" : "group alpha"
},
"two" : {
"members" : {
"-KM4oXjftRZZ5DXYt4B2" : true
},
"name" : "group beta"
},
"three" : {
"members" : {
"-KM4oXjftRZZ5DXYt4B2" : true
},
"name" : "group gamma"
}
},
"persons" : {
"-KLxjv9OnQB2l5Ohr-7I" : {
"groups" : {
"one" : true
},
"personName" : "name1",
"personTitle" : "title1"
},
"-KM4oXjftRZZ5DXYt4B2" : {
"groups" : {
"two" : true
},
"personName" : "name2",
"personTitle" : "title2"
}
}
}
APP.JS:
$scope.personsGroup = function(personObj){
var baseRef = new Firebase("https://un-cms-13264.firebaseio.com/");
var personsRef = baseRef.child('persons');
var groupsRef = baseRef.child('groups');
var res=[];
for(var i=0;i<Object.keys(personObj.groups).length;i++){
var groupKey=Object.keys(personObj.groups)[i]
res.push($firebaseArray(groupsRef.child(groupKey)));
};
return res;
}
HTML:
<div class="row" ng-repeat="person in persons">
<div class="col-lg-3"></div>
<div class="col-lg-3">{{person.personName}}</div>
<div class="col-lg-3"></div>
<div class="col-lg-3 groupsList">
<ul><li ng-repeat="group in personsGroup(person)">{{group.name}}</li></ul>
</div>
</div>

The best way would be to attach $firebaseArray to a $scope variable:
var ref = new Firebase("https://un-cms-13264.firebaseio.com/").child("persons").child(some-person).child("groups");
$scope.personsGroup = $firebaseArray(ref);
// When loaded
$scope.personsGroup.$loaded(function(data) {
// can do something
}, function(error) {
// error
});
How you determine some-person is up to you. You could query the persons tree and store all the persons or store it inside an array or object.
<ul>
<li ng-repeat="(key, value) in personsGroup">{{ key }}</li>
</ul>
I would not advise personGroup(person) because $firebaseArray is an asynchronous call and I feel like it could be real jumpy. Be smart with it, you could also just get the entire persons tree in one call if you wanted:
var ref = new Firebase("https://un-cms-13264.firebaseio.com/").child("persons");
$scope.persons = $firebaseArray(ref);
And do some iterating of that.

Related

How to collect sub arrays are new Arrays using `computed` method?

I have a list of arrays which contains sub arrays. how to collect those arrays and return them as new array?
here is my attempt but it does not work:
transactions: Ember.computed.map('model.cardList', function(card, index ){
return card.get('transactions');
},[]), // collecting all sub arrays but not works!!
sortedCards: Ember.computed(function(){
return this.get('model.cardList'); //length 4
}.property([])), //can i store here?
What is the correct way to collect the sub arrays from parent arrays? It is required for sorting purpose.
Thanks in advance.
Trying here, but nothing works:
Twiddle
Update
According to the twiddle, I would like to print the categoryName with fruit name(s) as a list.
If your solution at the end demands working with arrays of arrays and keeping them sorted, look at the following solution.
I have added a new field called origin to your model so that we have another field to sort by:
model(){
return {
"values" : [
{
"category" : "categoryD",
"origin": "Kongo",
"fruits" :[{"name":"banana"},{"name":"gova"}]
},
{
"category" : "categoryA",
"origin": "Italy",
"fruits" :[{"name":"apple"},{"name":"orange"}]
},
{
"category" : "categoryC",
"origin": "Marocco",
"fruits" :[{"name":"pineapple"}]
},
{
"category" : "categoryB",
"origin": "Brasil",
"fruits" :[{"name":"mongo"}]
}
]
}
}
And this is how your controller may look if you want to keep the sorting field dynamic:
import Ember from 'ember';
export default Ember.Controller.extend({
shouldSortByCategory: true,
values: Ember.computed.reads('model.values'),
valuesSortingDynamic: Ember.computed('shouldSortByCategory', function(){
return (Ember.get(this, 'shouldSortByCategory') ? ['category:asc'] : ['origin:asc'])
}),
valuesSortedDynamically: Ember.computed.sort('values', 'valuesSortingDynamic'),
actions: {
changeSortField(){
this.toggleProperty('shouldSortByCategory');
},
},
});
I do not care about sorting direction now (asc vs desc), but the field by which we sort is dynamic: category vs origin and is distinguished by the shouldSortByCategory flag.
The template looks pretty much the same:
<ul>
{{#each valuesSortedDynamically as |value|}}
<li>
{{#if shouldSortByCategory}}
<strong>{{value.category}}</strong> - {{value.origin}}
{{else}}
<strong>{{value.origin}}</strong> - {{value.category}}
{{/if}}
<ul>
{{#each value.fruits as |fruit|}}
<li>{{fruit.name}}</li>
{{/each}}
</ul>
</li>
{{/each}}
</ul>
Adjusted twiddle is to be found here: twiddle with dynamic sorting.
UPDATE
Cumulating all fruits into a single array preserving info about the category they belong to can be achieved as follows:
arrayOfFruitsArray: Ember.computed('model.values.[]', function(){
const values = this.get('model.values');
const cumulatedfruits = Ember.A();
values.forEach((value)=>{
const category = Ember.get(value, 'category');
const fruits = Ember.get(value, 'fruits');
fruits.forEach((fruit)=>{
fruit.category = category;
cumulatedfruits.pushObject(fruit);
})
});
return cumulatedfruits;
})
Updated twiddle.
In your case you don't even have to compute sub-arrays of array.
Given the model that you load as follows (taken from your twiddle):
export default Ember.Route.extend({
model(){
return {
"values" : [
{
"category" : "category1",
"fruits" :[{"name":"banana"},{"name":"gova"}]
},
{
"category" : "category2",
"fruits" :[{"name":"apple"},{"name":"orange"}]
},
{
"category" : "category3",
"fruits" :[{"name":"pineapple"}]
},
{
"category" : "category4",
"fruits" :[{"name":"mongo"}]
}
]
}
}
});
It's enough that you iterate over your arrays in the template:
<ul>
{{#each model.values as |value|}}
<li>
{{value.category}}
<ul>
{{#each value.fruits as |fruit|}}
<li>{{fruit.name}}</li>
{{/each}}
</ul>
</li>
{{/each}}
</ul>
Here is the respective Gist. Note that the only file I touched is the template.

Create array of objects in an object - Node.js

In the below code, 'info' object has a description, quantity, value. How to give them as an array(Indo property). How to retrieve in angular code.
details.customsDetail.itemDetails = {
currency : "2000USD",
weight : "lbs",
info : {
description : "descr",
quantity : "2",
value : "124",
}
};
Do you mean , indo property as array of objects?
details.customsDetail.itemDetails = {
currency : "2000USD",
weight : "lbs",
info : [{ // How to give this in a array.
description : "descr",
quantity : "2",
value : "124",
}]
};
you can assign the object to a variable and later you can push it to an array.
var backUp = angular.copy($scope.details.customsDetail.itemDetails.info);
$scope.details.customsDetail.itemDetails.info = [];
$scope.details.customsDetail.itemDetails.info.push(backUp);
console.log($scope.details.customsDetail.itemDetails)
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.details = {"customsDetail":{"itemDetails":{}}};
$scope.details.customsDetail.itemDetails = {
currency : "2000USD",
weight : "lbs",
info : {// How to give this in a array.
description : "descr",
quantity : "2",
value : "124",
}
};
var backUp = angular.copy($scope.details.customsDetail.itemDetails.info);
$scope.details.customsDetail.itemDetails.info = [];
$scope.details.customsDetail.itemDetails.info.push(backUp);
console.log($scope.details.customsDetail.itemDetails)
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
</div>

Angular how to have multiple selected

I have this array of objects. that holds somethings like this.
[
{
id: 1,
name: "Extra Cheese"
},
{
id: 2,
name: "No Cheese"
}
]
im iterating thru the array here
<select ng-model="item.modifiers" multiple chosen class="chosen-select" tabindex="4" ng-options="modifier._id as modifier.name for modifier in modifiers"></select>
The thing item.modifiers model that has an array of this 2 id
[
1,2
]
I want the multi select to auto selected the two ids that are in the item.model
I want the final result to look something like this
Your code is pretty much working already, maybe some of the variables are not assigned correctly (eg. id instead of _id)
angular.module('test', []).controller('Test', Test);
function Test($scope) {
$scope.modifiers = [
{
id: 1,
name: "Extra Cheese"
},
{
id: 2,
name: "No Cheese"
}
]
$scope.item = {};
// add this for pre-selecting both options
$scope.item.modifiers = [1,2];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<select ng-model="item.modifiers" multiple chosen class="chosen-select" tabindex="4" ng-options="modifier.id as modifier.name for modifier in modifiers"></select>
</div>
If I understand the question correctly, you're wanting to pre-select the two options.
To do this you will need to set your ng-model to point to the actual objects you are iterating over.
You will also need to change your ng-options to ng-options="modifier as modifier.name for modifier in modifiers" rather than just iterating over the ids.
Here's the relevant documentation under Complex Models (objects or collections)
https://docs.angularjs.org/api/ng/directive/ngOptions
Something like this should work:
HTML:
<select ng-model="$ctrl.item.modifiers"
ng-options="modifier as modifier.name for modifier in $ctrl.modifiers"
multiple chosen class="chosen-select" tabindex="4" >
</select>
JS:
app.controller("my-controller", function() {
var $ctrl = this;
$ctrl.modifiers = [{
id: 1,
name: "Extra Cheese"
}, {
id: 2,
name: "No Cheese"
}];
$ctrl.item = {
modifiers: []
}
$ctrl.$onInit = function() {
const id1 = 1;
const id2 = 2;
for (const modifier of $ctrl.modifiers) {
if (modifier.id === id1 || modifier.id === id2) {
$ctrl.item.modifiers.push(modifier);
}
}
}
}
Here's a pen showing the result:
http://codepen.io/Lahikainen/pen/WooaEx
I hope this helps...

AngularJS ng-class check if nested key/value pair exists and then add value as class

So, I have this nested array which I can't modify the structure of. I want to check if a key/value pair exists and if it does, add a corresponding class to the element in question.
I have been trying to use a variation of the expression:
ng-class="{ 'active' : data.indexOf('"name":"john"') >= 0 }"
However my expression is a bit more complicated and I'm afraid it's too much to use just like that. There's also the problem of using more than two level nested quotes.
Here's a fiddle using an array with a similar structure to what I'm working with:
http://jsfiddle.net/5tvmL2Lg/2/
HTML:
<body ng-app="myModule">
<div ng-controller="myController">
<div ng-repeat="hero in heroes">
<div ng-class="{ 'weight-\'hero.stats.indexOf('\'type\':\'weight\'').value\'' : hero.stats.indexOf('\'type\':\'weight\'') >= 0 }">
hello
</div>
</div>
</div>
</body>
JS:
var myModule = angular.module('myModule', []);
myModule.controller('myController', ['$scope', function($scope) {
$scope.heroes = [{
"firstname" : "clark",
"lastname" : "kent",
"stats" : [
{
"type" : "height",
"value" : "6'2"
},
{
"type" : "weight",
"value" : 220
},
{
"type" : "hair",
"value" : "brown"
}
]},
{
"firstname" : "bruce",
"lastname" : "wayne",
"stats" : [
{
"type" : "height",
"value" : "6'1"
},
{
"type" : "hair",
"value" : "black"
}
]},
{
"firstname" : "peter",
"lastname" : "parker",
"stats" : [
{
"type" : "height",
"value" : "5'11"
},
{
"type" : "weight",
"value" : 180
},
{
"type" : "hair",
"value" : "auburn"
}
]}];
}]);
In the end the goal would be to add a class named for example "weight-220" for the "clark kent" div, no class for the "bruce wayne" div, and "weight-180" for the peter parker div.
I know my problem is convoluted but any help would be greatly appreciated... :)
You don't need to add all your code logic into your ng-class. You can make it more complex (to check for the deeply-nested objects) by using a function that returns a string:
<div ng-repeat="hero in heroes">
<div ng-class="ClassBuilder(hero)">
hello
</div>
</div>
In your controller, add this function:
$scope.ClassBuilder = function(hero) {
for (var i = 0; i < hero.stats.length; i++) {
if (hero.stats[i].type == "weight") {
return "weight-" + hero.stats[i].value;
}
}
}
This will receive the hero object from each ng-repeat and check if the weight type exists. If so, it will use the corresponding value to return a string in your requested format, for example: "weight-220". Otherwise, it will return nothing and no class will be applied to that <div>.

Join queries in meteor angular using publish composite

I have two Collections Category and Feeds.
Category
{
"_id": "ADFGFDF",
"title" : "title",
}
Feeds
{
"_id": "DFSAHT",
"feeds" : "ds sdsd sds",
"categoryId" : "catId"
}
I need to get the result like this:
{
"_id": "ADFGFDF",
"title" : "title",
"categoryId" : "DFSAHT"
"category" : {
"_id": "DFSAHT",
"feeds" : "ds sdsd sds",
}
}
I tried using publish-composite and here it's my code.
Server
Meteor.publishComposite('feedscateg', function () {
return {
find: function () {
return Category.find({});
},
children: [
{
find: function (cat) {
return Feeds.find({ categoryID: cat._id });
}
}
]
}
});
In client Angular i tried this:
$scope.feeds = $meteor.collection(Category).subscribe('feedscateg');
And I am confused with the view part also.
publishComposite do not modify collection data, it will load Feeds and Category separately. If you want to get category of feed item just select it from client db.
$scope.getFeedCategory = function (feedItem) {
Category.findOne({'_id': feedItem.categoryId});
};

Resources