Using publish-composite with Angular-Meteor - angularjs

I have two Collections Articles and Categories let's say their documents are like this
Article
{
"_id": "blabla",
"title" : "title",
"description" : "description",
"categoryId" : "catId"
}
Category
{
"_id": "catId",
"title" : "category",
"description" : "description"
}
I want to make a subscription to make them like this
{
"_id": "blabla",
"title" : "title",
"description" : "description",
"category" : {
"title" : "category",
"description" : "description"
}
}
I tried using publish-composite and here it's my code.
Server
Meteor.publishComposite('articles', {
find: function() {
return Articles.find({}, { sort: {}, limit: 10 });
},
children: [
{
find: function(article) {
return Categories.findOne({ _id: article.categoryId });
}
}
]
});
And the client angularjs Controller is
angular.module("dee").controller("ArticlesListCtrl", ['$scope', '$meteor', function($scope, $meteor){
$scope.articles = $meteor.collection(Articles).subscribe('articles');
}]);
and the view is
{{ articles | json }}
the problem is it prints the article collection only without the relation.

adding to what #Deadly posted:
Publish composite makes it convenient to fetch related documents in a single subscription. How those documents are handled is still the same as if you made 2 separate subscriptions.
In your case, you would have two collections client side. One collection for Articles and one collection for Categories. Which Articles and which Categories that are in your local collection is based on that subscription you made.
// get a subscription to 'articles'. Use $scope.$meteorCollection so
// the subscription is destroyed when the $scope is destroyed. If you don't you will end up carrying these collections on to anther page.
$scope.$meteorSubscribe('articles').then(function() {
// This swill get you the articles from the local collection
$scope.articles = $scope.$meteorCollection(Articles);
// then you need to get the related Categories for the articles
$scope.getCategories = function(article) {
return $scope.$meteorObject(Categoris, article._id);
}
});

Controller:
angular.module("dee").controller("ArticlesListCtrl", ['$scope', '$meteor', function($scope, $meteor){
$scope.articles = $scope.$meteorCollection(Articles).subscribe('articles');
$scope.getCategory = function(article) {
return $scope.$meteorObject(Categories, article._id);
};
}]);
HTML:
<div ng-repeat="article in articles" ng-init="category=getCategory(article)"></div>
I also know better way to do it, but it doesn't work with angular and looks like nobody cares about it https://github.com/Urigo/angular-meteor/issues/720

Related

How to convert string into JSON data in view part of angularjs

Hi I have this data in JSON form, and I want to convert this data of option into json so that i can call optionName, optionSubName in a view part of angularjs
[
{
"heading": "MakeUp Type / Selection",
"option": "{"optionName":"Bridal Makeup","optionSubName":"Engagement,Tika / Godh Bharai,Ring Ceremony","optionDesc":""}",
"values": null
},
{
"heading": "Makeup Type",
"option": "{"optionName":"Experienced","optionSubName":"","optionDesc":{"products":"Bobbie Brown,Makeup Forever and Premium Makeup Products","Makeup_Include":"Straightening,Blow Drys,Tong Curls,Updo's","Drapping":"Yes","Lashes":"Yes","Nail_Polish_Change":"Yes","Extension_Available":"Yes","Airbrush_Available":"Yes"}}",
"values": null
}
]
I have already tried this but this is not working by using ng-repeat i have using this {{data.option.optionName | JSON}} but this is not working in my view part of angularjs, Please help me out how to reach at my goal ?
Use AngularJS forEach:
angular.forEach(object, iterator, [context])
object: The object interate over.
iterator: The iterator function or the code.
context: Object to become context (using this) for the iterator function.
var app = angular.module('app', []);
app.controller('AppController', ['$scope', '$http',
function($scope, $http) {
$http.get('json/array.json').success(function(data) {
$scope.array = data;
angular.forEach($scope.array, function(x){
console.log(x.optionName);
})
});
});
}
]);

How to fetch a single view from a backbone collection?

I have a simple backbone app that fetches a collection from a JSON file which works fine. But I really want to fetch a single modal from the collection. Ideally I want to fetch the model using the locale attribute.
How can I do this?
So far I have the following code,
var Item = Backbone.Model.extend({
defaults:{
"locale":"",
"name":"",
}
});
var ItemsCollection = Backbone.Collection.extend({
model: Item,
url: 'data/items.json'
});
var items = new ItemsCollection();
var itemView = new ItemView({model: items});
items.fetch({
success: function() {
itemView.render();
}
})
Json structure is this,
[
{
"locale": "gb",
"name": "British"
},
{
"locale": "de",
"name": "German"
}
]
Thanks

Loopback + Angular: `findById` Error. Expected response to contain an object but got an array

I'm trying to apply a filter for a chat room that makes it so that I only see messages that have a foreign key relationship to that chat room displayed, so I'm trying to pass shownMessages to the view. How do I do this effectively? The current error I'm dealing with is Error: [$resource:badcfg] Error in resource configuration for actionfindById. Expected response to contain an object but got an array. I'm searching as best as I can and still, nothing to my avail.
// for inside the room
// node - injection order is extremely important
.controller('InsideRoomController', ['$scope', '$q', 'ChatRoom', 'ChatMessage', '$stateParams', '$state', function($scope, $q,
ChatRoom, ChatMessage, $stateParams, $state) {
// we include Chatroom as a param to the controller and func since we work with that to display it's contents
// only show messages pertaining to that room
$scope.shownMessages = [];
ChatMessage
.findById({ id: $stateParams.messagesInChat })
.$promise
.then(function(showMessages) { // once we query to find chat rooms
$scope.shownMessages = shownMessages;
});
}])
relationsInChat is the name of the foriegn key relation I made in loopback between ChatRoom and ChatMessage which was generated in chat-room.json:
{
"name": "ChatRoom",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"city": {
"type": "string"
}
},
"validations": [],
"relations": {
"ChatMessagers": {
"type": "hasMany",
"model": "ChatMessager",
"foreignKey": ""
},
"chatMessages": {
"type": "hasMany",
"model": "ChatMessage",
"foreignKey": "messagesInChat"
}
},
"acls": [],
"methods": {}
}
Edit: How do I get all messages belonging to the chat via foreign key? I'm trying to use stateparams but not sure how
Try printing $stateParams.messagesInChat value.
As the error shows, it contains an array rather than object(means multiple value is present instead of single ID), but findByID accept only one value as you are finding the data for only one ID.
I got what I needed. Needed an include filter! http://loopback.io/doc/en/lb2/Include-filter.html
.controller('InsideRoomController', ['$scope', '$q', 'ChatRoom', 'ChatMessage', '$stateParams', '$state', function($scope, $q,
ChatRoom, ChatMessage, $stateParams, $state) {
// we include Chatroom as a param to the controller and func since we work with that to display it's contents
// only show messages pertaining to that room
$scope.shownMessages = [];
function getMsgs() {
//User.find({where: {vip: true}, limit: 10}, cb);
return (ChatRoom.find({include: ['ChatMessages']}))
};
$scope.shownMessages = getMsgs();
console.log($scope.shownMessages);
}])

AngularJS - Cannot read property 'navigable' of undefined

My app.run:
app.run([
'$q', '$rootScope', '$state', 'settings', 'datacontext',
function ($q, $rootScope, $state, settings, datacontext) {
settings.currentLang = settings.languages[0];
breeze.core.extendQ($rootScope, $q);
datacontext.getSideMenuItems().then(function (data) {
var startUp = undefined;
var rootUrl = '/app/views/';
/// this is the upper level used for side menu only
angular.forEach(data, function (value) {
// now loop thru the data for the $state items
angular.forEach(value.viewStates, function (viewState, key) {
if (key == 0) {
startUp = viewState.name;
}
var state = {
"url": '/' + viewState.name,
"parent": viewState.parentName,
"abstract": viewState.isAbstract,
"views": {}
};
angular.forEach(viewState.views, function (view) {
state.views[view.name] = {
controller: view.controllerName,
templateUrl: rootUrl + view.templateUrl + '.html'
};
});
$stateProviderRef.state(viewState.name, state);
});
$state.go(startUp);
});
});
}
My Data: [as JSON representation, ignore the Capitalization, breeze renames them lowercase]
[{
"$id": "1",
"Id": 2,
"Icon": "fa-home",
"IsActive": "active",
"IsShared": false,
"OrderNum": 1000,
"Title": "Dashboards",
"FK_DbModuleId": 1,
"DBoardModule": null,
"ViewStates": [
{
"$id": "2",
"Id": 2,
"IsAbstract": false,
"Name": "PersDboards01",
"ParentName": "root",
"OrderNum": 1,
"FK_ViewGroupId": 2,
"ViewGroup": {
"$ref": "1"
},
"Views": [
{
"$id": "3",
"Id": 4,
"ControllerName": "MyDashboardCtrl",
"Name": "container#",
"TemplateUrl": "dashboards/myDashboard",
"FK_ViewStateId": 2,
"ViewState": {
"$ref": "2"
}
},
{
"$id": "4",
"Id": 5,
"ControllerName": "LeftPanelCtrl",
"Name": "leftPanel#",
"Title": "null",
"TemplateUrl": "shell/html/left-panel",
"FK_ViewStateId": 2,
"ViewState": {
"$ref": "2"
}
}
]
}
]
I know the Json has the properties capitalized but I am not really using JSON, I just copied this off of fiddler which got it from my Web API.
I understand that the error "Cannot read property 'navigable' of undefined" means I am not defining the child state after I define the parent state, but I cannot see where I am doing that.
Does anyone know a better way to structure the app.run?
UPDATE:
I found my error, see below.
Solved:
Indeed the error was due to my creating child states before establishing the parent state.
I looked at my database and noticed the parent state LAST in my que:
Id : 150
IsAbstract : 1
Name: "root"
ParentName: ""
.....
Had I made sure to make it first the problem would not have occured.
Id : 1
IsAbstract : 1
Name: "root"
ParentName: ""
.....
I recognize this situation will not help many other than as a reminder to make sure your parent state is the first state in your loop when creating dynamic states/views
The code you included above does not reference 'navigable' at all, so it cannot be the source of this error. Please either include the additional files where that reference is being made, or better still, post a Plunkr that illustrates the problem.
I'm posting this as an answer rather than a comment because there's an additional detail that may help you find the actual source of the error, and you may find that you don't need any further help when you find it. In Angular it's very common for error locations to be hard to find. Many of its mechanisms have "deep" calls stacks, especially when an error is triggered either by the injector or digest cycle. What you end up finding is that the error itself is happening somewhere else from where you think it is.
I think that it is likely you are encountering the same error reported here:
https://github.com/angular-ui/ui-router/issues/488
You appear to be using AngularJS with Angular UI Router and Breeze, all together. The error reported there is identical to yours, and if you re-examine your code and follow what the others reported on that thread I think you will find that your problem is fixable... but has little/nothing to do with your actual code above!
The issue here is related to wrong Upper and Lower case JSON property naming during the processing. There is a working plunker - which calls console.log(state) at the end of JSON processing.. to show the result (do not foget to start the console with F12)
A snippet comparison would be like this
angular.forEach(response.data, function (value) {
// NO viewStates
// but ViewStates
angular.forEach(value.ViewStates, function (viewState, key) {
if (key == 0) {
startUp = viewState.Name; // instead of name
}
var state = {
"url": '/' + viewState.Name, // instead of name
"parent": viewState.ParentName, // instead of parentName
"abstract": viewState.IsAbstract, // instead of isAbstract
"views": {}
};
// No views
// but Views
angular.forEach(viewState.Views, function (view) {
state.views[view.Name] = {
controller: view.ControllerName, // instead of controllerName
templateUrl: rootUrl + view.TemplateUrl + '.html'
};
});
$stateProviderRef.state(viewState.Name, state); // instead of name
console.log(state)
});
});
because the JSON is like that (see Upper case at the begining):
"ViewStates": [{
"IsAbstract": false,
"Name": "PersDboards01",
"ParentName": "root",
...
},
"Views": [{
"ControllerName": "MyDashboardCtrl", // ControllerName
"Name": "container#", // Name
"TemplateUrl": "dashboards/myDashboard", // Templateurl
...
The working plunker plunker (just loging the result into console) shows that the rest of the code should be working

angularjs + jsonp returns a fail

I am trying to build a sample app that will grab data using JSONP to populate. I have it put up at http://angular.onagrag.com/ and clicking on register.
The file I am trying to load is at http://api.onagrag.com/data.json
When I access http://angular.onagrag.com/register it fires the error method of the object (and it fires it twice)
here is the angular js file that I am using (it is also located at http://angular.onagrag.com/js/test.js
It runs fine if I use local data (e.g. use the $http.get method instead of the $http.jsonp method), but will not work with jsonp. Any help is appreciated!
var App = angular.module('popdust', ['ngResource']).config(['$locationProvider', function($location) {
$location.html5Mode(true).hashPrefix('!')
}]);
App.config(['$routeProvider', function($routes) {
$routes.when('/register',{
templateUrl : '/templates/register.html',
controller : RegisterCtrl
});
$routes.when('/',{
templateUrl : '/templates/home.html',
controller : HomeCtrl
});
}]);
var HomeCtrl = function($scope, $http, $location) {
$scope.title = 'We are home';
$scope.obj = ['one', 'two','three'];
};
var RegisterCtrl = function($scope, $http, $location) {
$scope.title = 'Register!';
$scope.handleData = function(data){
$scope.fields = data;
}
$scope.fetchjsonp = function(){
$http.jsonp('http://api.onagrag.com/data.json?callback=JSON_CALLBACK').success(function(data){
alert("success");
}).error(function(data, status, headers, config) {
alert("YOU FAIL");
});
}
$scope.fetch = function(){
$http.get('js/data.json').success($scope.handleData);
}
$scope.fetchjsonp();
};
HomeCtrl.$inject = ['$scope','$http','$location'];
RegisterCtrl.$inject = ['$scope','$http','$location'];
Looks to me like the problem is with your resource. When I check http://api.onagrag.com/data.json?callback=JSON_CALLBACK I get the following response:
[{
"id" : "first_name",
"title" : "First Name",
"description" : "The name your parents gave you"
},{
"id" : "last_name",
"title" : "Last Name",
"description" : "In Spanish, it's called your apellido (or something like that)"
}]
This is not a valid JSONP response. With the request parameter callback=nameOfCallbackFn the response should be a single function call to a function named nameOfCallbackFn (with the result as it's only parameter).
Update: The server that serves the JSONP must read the callback request parameter and respond with a file that does a method call to the request method name. When you use the angular $http.jsonp method, angular will change the callback request parameter to the correct angular jsonp callback method name (atm they seem to be named angular.callback._0, ..._1 etc). You can't serve a static file as this name might change from one request to the other. This was not clear in my original answer.
Something like this:
nameOfCallbackFn ( [{
"id" : "first_name",
"title" : "First Name",
"description" : "The name your parents gave you"
},{
"id" : "last_name",
"title" : "Last Name",
"description" : "In Spanish, it's called your apellido (or something like that)"
}] );
Where nameOfCallbackFn is specified by angular.
JSONP has some potential security vulnerabilities - you can read more about them and how to prevent them in your angular app here.

Resources