Angular component does not render template - javascript

Based on a tutorial from UI-Router
(https://ui-router.github.io/ng1/tutorial/hellogalaxy) I have these states in my Angular app:
angular
.module('appRoutes', ["ui.router"])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
// An array of state definitions
var states = [
{ name: 'home', url: '/', component: 'home' },
{ name: 'about', url: '/about', component: 'about' },
]
// Loop over the state definitions and register them
states.forEach(function(state) {
console.log(state.component)
$stateProvider.state(state);
});
$urlRouterProvider.otherwise('/');
}]);
Here is my other file that contain module declaration:
'use strict';
var talentforceApp = angular.module("talentforce", []);
angular
.module('TalentForce_Application', [
'appRoutes',
'talentforce',
'ngResource'
]);
And the file for one of those simple components:
talentforceApp.component('about', {
template: '<h3>About TalentForce</h3>'
})
When I run it, my console gives no errors. I checked and the state and component is indeed saved. It just doesn't render. When I click the About button of my app, there is no template, just blank and no errors. It is hard to debug since there are no errors. What am I missing here?

angular.module('appRoutes').component('about', {
template: '<h3>Template</h3>'
})

You have most likely found a solution for this but here it goes anyway.
In the example, all components are part of the same angular module ('hello') whereas you have added to components into a separate module.
You need to add TalentForce_Application as a dependency to your main module appRoutes.
angular
.module('appRoutes', ["ui.router", "talentforce"])
...

Related

Promises getting resolved twice in AngularJS

I am learning to use angularjs with requirejs and angular-ui-router. I created a plunker over here http://plnkr.co/edit/iA8zVQWP3ypRFiZeRDzY?
<div ui-view ></div>
<script data-main="require-config" src="http://requirejs.org/docs/release/2.1.20/r.js"></script>
The startup file index.html has a reference to require-config.js which loads the required third-party javascript libraries, resolves dependencies and bootstraps my module which is in app.js
angular.element().ready(function() {
//bootstrap the app manually
angular.bootstrap(document,['myApp']);
});
I am using ui.router to resolve appropriate states and navigate to the appropriate page
define(['angular', 'story'
], function(angular) {
angular.module('myApp', ['ui.router', 'ui.bootstrap', 'myApp.story'])
.controller('TabController', ['$scope', '$state', function($scope, $state) {
$scope.tabs = [
{route: 'main.story', label : "Promises", active : false},
//more routes here.
];
$scope.go = function(route){
$state.go(route);
};
$scope.active = function(route){
return $state.is(route);
};
$scope.$on("$stateChangeSuccess", function() {
$scope.tabs.forEach(function(tab) {
tab.active = $scope.active(tab.route);
});
});
}])
$stateProvider will route to appropriate state.
config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
abstract: true,
url: '/main',
templateUrl: 'tabs.html',
controller: 'TabController'
})
.state('main.story', {
url: '/story',
templateUrl: 'story.html',
controller: 'storyController'
})
$urlRouterProvider.otherwise('/main/story');
}])
and ui.bootstrap to use tabs provided by bootstrap library.
<tabset>
<tab
ng-repeat="t in tabs"
heading="{{t.label}}"
select="go(t.route)"
active="t.active">
</tab>
</tabset>
This plunker is working with bugs. When I look at the Network in Chrome, the json files ( chapter-1.json and chapter-2.json ) are getting loaded/resolved twice.
I also verified the code without using requireJS and it is working (loading scripts using script tag manually) fine. The promises are getting resolved only once. So, there is some configuration that I am doing incorrectly while using requirejs.
I also verified the files getting loaded twice using $httpProvider.interceptors as well.
How can I resolve this?
In app.js, you are indicating storyController as the controller for your main.story state, but you have an ng-controller="storyController" inside your story.html.
The result is that you are initializing two storyControllers and each one calls .getText() once.
You can solve this by removing the ng-controller from your story.html:
<body>
<div>
{{chapter1}}<br>
{{chapter2}}
</div>
</body>

Sub-views in Angular UI router and Controller inheritance?

I have a view state like this, with 3 views:
(function() {
'use strict';
angular.module('pb.tracker').config(function($stateProvider) {
$stateProvider.state('tracker', {
url: '/tracker',
controller: 'TrackerController as tracker',
data: {
pageTitle: 'Parcel Tracker',
access: 'public',
bodyClass: 'tracker'
},
resolve: {
HistoryResolve: function($log, MockDataFactory) {
return MockDataFactory.query({
filename: 'trackingdata'
});
}
},
views: {
'': {
templateUrl: 'modules/tracker/templates/tracker.html'
},
'controls#tracker': {
templateUrl: 'modules/tracker/templates/tracker-controls.html'
},
'content#tracker': {
templateUrl: 'modules/tracker/templates/tracker-details.html'
}
}
});
});
})();
I want to use the controller TrackerController for all the views in the state. I thought they would simple inherit the parent one.
But so far, even a simple log does not show in the console. The controller is
(function() {
'use strict';
angular.module('pb.tracker').controller('TrackerController', function($log, HistoryResolve) {
var _this = this;
// _this.packageHistory = HistoryResolve;
$log.debug('foo');
});
})();
So, my console should read "foo" regardless, yes? Nothing in the console. No errors. The works fine, the views load the templates. I am only stuck on the controller. I've never run into this.
UPDATE
OK, I am trying to define a parent state, and assign the controller to that. However, what I have below is no yielding nothing at all in the browser...
(function() {
'use strict';
angular.module('pb.tracker').config(function($stateProvider) {
$stateProvider.state('tracker', {
url: '/tracker',
abstract: true,
controller: 'TrackerController as tracker',
data: {
pageTitle: 'Parcel Tracker',
access: 'public',
bodyClass: 'tracker'
},
resolve: {
HistoryResolve: function($log, MockDataFactory) {
return MockDataFactory.query({
filename: 'trackingdata'
});
}
}
})
.state('tracker.details', {
url: '/tracker/details',
views: {
'': {
templateUrl: 'modules/tracker/templates/tracker.html'
},
'controls#tracker': {
templateUrl: 'modules/tracker/templates/tracker-controls.html'
},
'content#tracker': {
templateUrl: 'modules/tracker/templates/tracker-details.html'
}
}
});
});
})();
When you define named views (using the views property, aka "named views"), the template properties of the state are overriden by each named view. From the documentation:
If you define a views object, your state's templateUrl, template and templateProvider will be ignored. So in the case that you need a parent layout of these views, you can define an abstract state that contains a template, and a child state under the layout state that contains the 'views' object.
Note that a template is always paired with a controller. So since it doesn't use the template properties, there's no need for it to instantiate the controller. You have two choices:
Use specify the controller for each view. This will instantiate a controller for each named view, probably not what you want.
Create a parent state to this state, which is abstract and uses the controller. Note that your state above doesn't have a child/parent relationship, it's just one state w/some named views.

how to call a ui-router state declared in another angular module

I have created two angularjs module of the same application. How can I call from the module A the state x declared in the module B? Do you have any idea or workaround?
when I call the state x in this way
$state.go('x')
from the module A, it isn't found
// This is your parent module
var app = angular.module('app', [
'ui.router',
// Application modules
'moduleA',
'moduleB'
]);
// This is your child module 1
var moduleA = angular.module('moduleA', ['ui.router']);
moduleA.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('moduleA', {
url: '/route1',
controller: 'moduleAController',
template: "<div>Test</div>"
});
}]);
// This is your child module 2
var moduleB = angular.module('moduleB', ['ui.router']);
moduleB.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('moduleB', {
url: '/route2',
controller: 'moduleBController',
template: "<div>Test</div>"
});
}]);
Explanation - With this you have one parent module with 2 child modules. Child modules services, controllers and directives can be used across these 3 modules without any dependency injection.

AngularJS + Routing + Resolve

I'm getting this error:
Error: Error: [$injector:unpr] http://errors.angularjs.org/1.3.7/$injector/unpr?p0=HttpResponseProvider%20%3C-%20HttpResponse%20%3C-%20DealerLeads
Injector Unknown provider
Here's my router (ui.router):
$stateProvider
.state('main', {
url: "/main",
templateUrl: "views/main.html",
data: { pageTitle: 'Main Page' }
})
.state('leads', {
url: "/leads",
templateUrl: "views/leads.html",
data: { pageTitle: 'Dealer Leads' },
controller: 'DealerLeads',
resolve: DealerLeads.resolve
})
Here's my Controller:
function DealerLeads($scope, HttpResponse) {
alert(JSON.stringify(HttpResponse));
}
Here's my resolve:
DealerLeads.resolve = {
HttpResponse: function ($http) {
...
}
}
The data is getting to the controller, I see it in the alert. However, after the controller is done, during the rendering of the view (I think), the issue seems to be happening.
The final rendered view has two controllers: One main controller in the body tag, and the second controller 'DealerLeads' inside of that. I've tried removing the main controller, and the issue is still present.
What am I doing wrong? Is there any more code that is necessary to understand/resolve the issue?
When you use route resolve argument as dependency injection in the controller bound to the route, you cannot use that controller with ng-controller directive because the service provider with the name HttpResponse does not exist. It is a dynamic dependency that is injected by the router when it instantiates the controller to be bound in its respective partial view.
Just remove the ng-controller="DealerLeads" from the view and make sure that view is part of the html rendered by the state leads # templateUrl: "views/leads.html",. Router will bind it to the the template for you resolving the dynamic dependency HttpResponse. If you want to use controllerAs you can specify that in the router itself as:-
controller: 'DealerLeads',
controllerAs: 'leads' //Not sure if this is supported by ui router yet
or
controller: 'DealerLeads as leads',
Also when you do:
.state('leads', {
url: "/leads",
templateUrl: "views/leads.html",
data: { pageTitle: 'Dealer Leads' },
controller: 'DealerLeads',
resolve: DealerLeads.resolve
})
make sure that DealerLeads is accessible at the place where the route is defined. It would be a better practice to move the route definition to its own controller file so that they are all in one place. And whenever possible especially in a partial view of a route it is better to get rid of ng-controller starting the directive and instead use route to instantiate and bind the controller for that template. It gives more re-usability in terms of the view as a whole not being tightly coupled with a controller name and instead only with its contract. So i would not worry about removing ng-controller directive where router can instantiate the controller.
I'm not completely understand you question, and also not an expert as #PSL in angular.
If you just want to pass some data into the controller, maybe below code can help you.
I copied a piece of code from the project:
.state('masthead.loadTests.test',{
url: '/loadTests/:id',
templateUrl: 'load-tests/templates/load-test-entity.tpl.html',
controller: 'loadTestEntityCtrl',
data: { pageTitle: 'loadTests',
csh: '1005'
},
resolve: {
// Get test entity data before enter to the page (need to know running state)
LoadTestEntityData: [
'$stateParams',
'$state',
'LoadTestEntity',
'LoggerService',
'$rootScope',
function ($stateParams, $state, LoadTestEntity, LoggerService, $rootScope) {
// Get general data
return LoadTestEntity.get({id: $stateParams.id},function () {
},
// Fail
function () {
// When error navigate to homepage
LoggerService.error('error during test initiation');
$state.go('masthead.loadTests.list', {TENANTID: $rootScope.session.tenantId});
}).$promise;
}
]
}
})
Here the LoadTestEntityData is the data we injected into the controller,
LoadTestEntity and LoggerService are services needed for building the data.
.factory('LoadTestEntity', ['$resource', function ($resource) {
return $resource(
'/api/xxx/:id',
{id: '#id'},
{
create: {method: 'POST'},
update: {method: 'PUT'}
}
);
}])
Hope it helps!

Injecting services/constants into provider in Angularjs

The problem here is I am able to access the getRoutes(), but I am unable to access the injected constant -"configuration". What am I missing? Thanks.
(function () {
'use strict';
var app = angular.module('app');
app.constant('configuration', {
PARTIAL_PATH: "/app/components/partials"
});
app.module('app', [
'routeService'
]);
var routeServiceModule = angular.module('routeService', ['common']);
routeServiceModule.provider('routeConfig',function () {
this.getRoutes = function () {
return [
{
url: '/login',
config: {
title: 'admin',
templateUrl: 'app/components/login/login.html'
}
}, {
url: '/',
config: {
templateUrl: 'app/components/dashboard/dashboard.html',
title: 'Dashboard'
}
}
];
};
this.$get = ['configuration', function (configuration) {
var service = {
getRoutes: getRoutes(),
configuration: configuration.PARTIAL_PATH
};
return service;
}];
app.config(['$routeProvider', 'routeConfigProvider', function ($routeProvider, routeConfigProvider) {
//Unable to get the configuration value
console.log(routeConfigProvider.configuration);
//Console is returning as "undefined"
routeConfigProvider.getRoutes().forEach(function(r) {
$routeProvider.when(r.url, r.config);
});
$routeProvider.otherwise({ redirectTo: '/' });
}
]);
})();
Created a plunkr demo : http://plnkr.co/edit/2TIqgxMxBJEPbnk2Wk6D?p=preview
(Regarding your last comment, with the plnkr)
The result is expected.
At config time (within app.config() ), you access raw providers, as you defined them, which allows you to call "private" methods or fields (testItem1) and to configure it for run time use. "private" because they won't be accessible at run time.
At run time (within app.run() and the rest of your app), when you ask for a dependency for which you wrote a provider, the angular injector hands you the result of the $get method of your provider, not the provider itself, so you can't access the "private" function.
This page was my path to enlightenment : AngularJS: Service vs provider vs factory
I think you may be over complicating the route stuff. You may have a very good reason for it but as I do not know it may I suggest keeping it simple with something more like this:
MyApp.config(function ($routeProvider) {
$routeProvider.when('/home', {
templateUrl: 'home.html',
controller: 'HomeController',
activeTab: 'home'
})
};
MyApp.controller('HomeController', function ($route) {
console.log($route.current.activeTab);
});
I would be interested in knowing why you may not able to use this routing pattern or purposely chose something different.
I think it has to do with the way you are creating your initial module. Try this:
var app = angular.module('app', []);
app.constant('configuration', {
PARTIAL_PATH: "/app/components/partials"
});
var routeServiceModule = angular.module('routeService', ['app']);

Categories