AngularJS - Cannot read property 'navigable' of undefined - angularjs

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

Related

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);
}])

How do I get a single value from a json file using angular (without using ng-repeat)?

I have a json file with the following data:
{
"favicons": [
{
"36x36”: "36x36.png",
"48x48": "48x48.png",
"57x57": "57x57.png"
}
],
"header": [
{
"imageUrl": "logo.png",
"subTitle": “blah”,
"backgroundColor": "#c30909"
}
]
}
I'd like to retrieve the value of favicons.36x36 without using ng-repeat.
I have this in my app.controller:
app.controller('myCtrl', function($scope, $http) {
$http.get("data.json").then(function (response) {
$scope.faviconData = response.data.favicons;
})
});
Using {{faviconData}} in my HTML, I can output the entire array.
But {{faviconData.36x36}} results in a parse syntax error.
I have also tried faviconData[0].36x36 but this also results in an error.
Do this
{{faviconData[0]['36x36']}}

Using publish-composite with Angular-Meteor

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

Angular Factory Manipulating Data (CRUD) with function in the Factory

I have a simple Angular App that uses a factory to pull a list of items from a "JSON" file. Eventually this will be connected to a database but for now I'm starting with just pulling from a static file. The JSON file contains an array of items. I'm really trying to understand how do I get a reference to my data in the factory after the promise has been returned to the controller.
My Factory is setup as follows:
angular.module("myApp").factory("ServiceTypeFactory", ['$http', function ($http ) {
return {
ServiceTypes: function () {
return $http.get('json/servicetypes.json').success
(
function (data) {
return data;
});
},
find: function (id) {
return _.findWhere(data, {ID:id}); // Not sure how to get access to the data
}
}
}]);
This works great I can share the Factory across multiple controllers. The part I'm missing is how do I reference a specific array item from my json file and update it in my controller. I'm not following how to get a reference to the actual data so when I modify the item in one controller it the change would be reflected in another controller.
In both of my controllers I have the following code to get a reference to the data initially.
var popService = function (data) {
$scope.ServiceTypes = data;
}
// IF at ANY time the Service Types have not been loaded we will populate them.
if (typeof $scope.ServiceTypes === "undefined") {
ServiceTypeFactory.ServiceTypes().success(popService);
}
My understanding is my $scope.ServiceTypes has really a reference to the data. How do I back in my factory in a function get access to the actual single source of my data. I get that the factory returns the data with functions an object but I'm missing how to reference this data back in my factory to manipulate it. In the future I want to perform CRUD operations on it for the time being I'm just trying to work out the mechanics.
What my JSON file looks like:
{
"serviceTypes": [
{
"ID": "1001",
"ServiceTypeName": "111111",
"Description": "aaaaaaa"
},
{
"ID": "1002",
"ServiceTypeName": "222222",
"Description": "bbbbbbb"
},
{
"ID": "1003",
"ServiceTypeName": "3333333",
"Description": "ccccccc"
},
{
"ID": "1004",
"ServiceTypeName": "444444",
"Description": "dddddddd"
},
{
"ID": "1005",
"ServiceTypeName": "5555555",
"Description": "eeeeeee"
}
]
}
Just needed to clean the code up a little. Watching a couple of quick example on egghead.io made it clear.

Sub-promises in AngularFire - selecting related children by ID?

I have a json collection I've uploaded to my firebase, the sites and tools are related via arrays located in the former that point to keys in the latter
"sites": {
"s001": {
"name": "ACT-105",
"description": "Intro Accounting",
"type": "course",
"thumbnail": "debate",
"toolCount": 4,
"tools" : ["t001","t002","t003"]
},
"s002": {
"name": "ART-201",
"description": "Pottery Lab",
"type": "course",
"thumbnail": "sculpture",
"toolCount": 4,
"tools" : ["t001","t002","t003","t004"]
},
"tools": {
"t001": {
"name": "main-tool",
"title": "Home",
"description": "Main tool",
"thumbnail": "home.jpeg"
},
"t002": {
"name": "announce-tool",
"title": "Announcements",
"description": "System Announcements",
"thumbnail": "announcements.jpeg"
},
I open a url and promise; then grab the current site and its array of related tools in an array, then open another promise to loop through and get all the related tools. From the alert, it appears to only grab one tool then quits.
angular.module("foo", ["firebase"]).
controller("MyCtrl", ["$scope", "angularFire", function($scope, angularFire) {
var dbRef = "https://sampledb.firebaseio.com";
var siteRef = new Firebase(dbRef + "/sites/s003");
var promise = angularFire(siteRef, $scope, "site", {});
var sitetools = [];
promise.then(function() {
sitetools = $scope.site.tools;
alert("tools " + sitetools);
}).then(function () {
var toolList = [];
for (var i=0;i<sitetools.length;i++)
{
alert("tool " + sitetools[i]);
toolList.push(getTool(dbRef,toolId));
}
$scope.tools = toolList;
});
}]);
var getTool = function(dbRef,toolId) {
var toolitem;
var toolRef = new Firebase(dbRef + "/tools/" + toolId);
alert(toolRef);
var promise = angularFire(toolRef, $scope, "tool", {});
promise.then(function() {
alert("found tool " + toolId);
toolitem = $scope.tool;
});
return toolitem;
};
The fiddle is here: http://jsfiddle.net/5n9mj/1/
First of all, you should have got the alerts (3 of them) since the iterations went as expected, but the return of the getTool() function is always null: it returns before the promise is resolved and local tooitem variable is not accessible anymore.
Remember that all Firebase calls are async. Also, this code:
var promise = angularFire(toolRef, $scope, "tool", {});
promise.then(function() {
alert("found tool " + toolId);
toolitem = $scope.tool;
}
will trigger race conditions: $scope.tool is bound with the Firebase and there is no guarantee that it would be bound in a specific order and if there will be enough processor time to push it into your array before another promise is resolved. That's why it's better to listen on the value change using Firebase reference than to use angularFire and explicitly bind it to the scope variable.
I think you overcomplicated the code a little bit, you don't have to create new Firebase references every time you are binding your scope variables (unless you're going to use the reference later) with angularFire: angulerFire can accept String url as it's first param.
http://jsfiddle.net/oburakevych/5n9mj/10/
If I were you I would wrap the Tool functionality into a directive with a separate controller, so that each tool will have it's own scope, something like this:
<ul ng-repeat="toolId in tools">
<li><tool tool-id="{{toolId}}"/></li>
</ul>
var promise = angularFire(siteRef, $scope, "site", {});
promise.then(function() {
$scope.broadcast("event:SITE_INITIALIZED");
});
.controller("MyCtrl", ["$scope", "angularFire", '$timeout', function($scope, angularFire, $timeout) {
$scope.$on("event:SITE_INITIALIZED", function() {
angularFire(siteRef + "/item/" + $scope.itemId, $scope, "item", {});)
});

Resources