Using $routeProvider for dynamic routing and compiling angular code - javascript

this has been bugging me for days and i can't figure this out.
i have a website that adds articles at certain points so i figured i shouldn't need to change the routing every time i add a page. so i added this to my project:
$routeProvider.when ('/pages/:page', { templateUrl: 'page.html', controller: 'pageCtrl' });
then i use this for the pageCtrl:
app.controller('pageCtrl', function ($scope, $http, $q, $routeParams, $sce, $location) {
$http.get("partials/" + $routeParams.page + ".html")
.then(function(ret) {
$scope.content = $sce.trustAsHtml(ret.data);
}, function(err) {
$location.path("/404")
});
});
then in the webpage i put a
<div ng-view ng-bind-html="content">{{content}}</div>
and all works well except when i put angular code in there. it seems that it will only parse regular html code but not the ng-stuff. i think i should put a $compile in there somewhere. but i tried all combinations i could think of but none work.
things i tried:
$scope.content = $compile($sce.trustAsHtml(ret.data))($scope);
var e=angular.element($sce.trustAsHtml(ret.data));
c=$compile(e);
$scope.content = c;
c($scope);
and several others that didnt do anything at all..
what's the right way to add content in a view and have angular directive work properly?

This should work well with ng-include within your page.html template:
page.html:
<h1>Page {{name}}</h1>
<div ng-include="contentUrl"></div>
Then your pageCtrl can set these to:
app.controller("pageCtrl", function($scope, $routeParams){
$scope.name = $routeParams.page;
$scope.contentUrl = $routeParams.page + ".html";
})
Here's a working plunker

Related

Second Controller not responding

For some reason, the second Controller isn't receiving the data from the Service.
I'm trying to make the communication between two Controllers using one Service for it.
The View:
<div class="btn-wrapper" ng-controller="FirstController">
<a ng-href="" ng-click="doPath()" id="go" class="button">GO!</a>
</div>
The FirstController.js:
angular.module('app')
.controller('FirstController', function($scope, sharedService) {
$scope.doPath = sharedService.searchPath;
});
The sharedService:
angular.module('myServices', [])
.service('sharedService', function($rootScope) {
this.searchPath = function() {
console.log("I got the service!");
$rootScope.$broadcast('Search', {
data: 'something'
});
}
});
And the SecondController.js
angular.module('app')
.controller('SecondController', function(sharedService, $scope) {
$scope.$on('Search', function(event, data){
console.log(data);
//this.search(); => I intent to run this function after this
});
});
The event is dispatched by a button in the View, that calls the doPath() function. This function does communication with the Service sharedService and the message "I got the service" is displayed.
However, the app stops here. And the communication between Service and the second Controller, using $rootScope.$broadcast, seems that not happening (the data isn't showing on console, neither any error).
I found some solutions here. I have tried already all of answers, so the problem is not the same, cause still not working.
EDIT
The ngRoute is here (app.js):
angular.module('app', ['ngRoute', 'myServices'])
.config(function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'FirstController'
})
.otherwise({
redirectTo: '/'
});
});
As everyone suggested 'Instantiation' of the Second controller is needed.
<div ng-controller="firstController">
//code
</div>
<div ng-controller="secondController">
//code
</div>
Like above.
I know you have used 'ngRoute'. Until you change your view the second controller will not be loaded in 'ngRoute' whereas in above code both the controllers are in the same view. That is why above code works and 'ngRoute' does not.
SecondController is not instantiated by Angular because you are referring only FirstController from html. You need to instantiate the SecondController on the same html using parent child or sibling relationship depending on your application.

Angular Controller returns 404 on a Route Parameter

I'm building my first web app with Node.js and AngularJs. My problem lies in this code here:
var app = angular.module('Martin', ['ngResource','ngRoute']);
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'partials/home.html',
controller: 'PageCtrl'
})
.when('/etx/:id', {
templateUrl: 'partials/page.html',
controller: 'PageCtrl'
});
}]);
app.controller('PageCtrl', ['$scope', '$resource', '$routeParams',
function($scope, $resource, $routeParams){
console.log('Got here');
var Page = $resource('/api/pages/:id');
Page.get({ id: $routeParams.id }, function(page){
$scope.page = page;
});
}]);
From what I understand, if I were to request /etx/mypage, the function in PageCtrl should be run, but when I try to pull it up in a browser, I get a 404 error and nothing is printed to the console.
I tested it with the home page ('/'), and the controller works fine then.
As #Claies identified, the problem was I forgot the octothorpe (or hashtag if you want to be less cool) in the URL. So it should not be etc/mypage, but #/etc/mypage. This behavior is less than ideal in many cases (including mine), so I recommend disabling this with HTML5 mode for links.

Angular Controller on Custom Directive

Here is my controllers.js file
(function(ctx,angular){
'use strict';
angular.module('app.controllers')
.controller('SearchMasterController',['$scope',function($scope){
//My Code
}]);
})(window, angular);
And this is my directives.js file
(function(ctx,angular){
function ControllerFunction(){
//My Controller Code
}
var directiveConfig = {
restrict:'E',
templateUrl:'path/to/acco.html',
controller: ControllerFunction
}
angular.module('app.directives')
.directive('acco', function(){
return directiveConfig;
});
})(window, angular);
Now my question is, can I use this acco directive with some different controller. Ideally, is there any way to get it working like
<acco ng-controller="SearchMasterController"></acco> ?
I tried doing,
<acco>
<div ng-controller="SearchMasterController"></div>
</acco>
and it seems to work.
Is it possible to use
<acco ng-controller="SearchMasterController"></acco> ?
The latter alternative looks ugly to me.
nice to heard this type of access, i have tried
<acco>hi{{name1}}
<div ng-controller="SearchMasterController">{{name1}}</div>
</acco>
<acco ng-controller="SearchMasterController">{{name1}}</acco>
<script>
angular.module('myApp', [])
.controller('SearchMasterController', ['$scope', function ($scope) {
//My Code
console.log("search");
$scope.name1 = 'james';
}])
.directive('acco', function () {
return{
restrict: 'E',
templateUrl: 'acco.html',
controller: function($scope) {
//My Controller Code
console.log("cntrlr fn");
$scope.name1 = 'semaj';
}
};
});
</script>
#that time i getting output as
cntrlr fn
search
cntrlr fn
means if we are using like
<acco>hi{{name1}}
<div ng-controller="SearchMasterController">{{name1}}</div>
</acco>
then we can access both controllers but when we are using like
<acco ng-controller="SearchMasterController">{{name1}}</acco>
we can't access SearchMasterController and it's not loaded also..
Yes you can use some different controller for your directive, but there is some best practice
Use controller when you want to expose an API to other directives. Otherwise use link.
The way you tried to use controller doesn't make much sense
<!--here acco and ng-controller both are directives,
in your directive's 'ControllerFunction' and ng-controller's 'SearchMasterController'
has the same controll (scope) for 'acco' rendered html.
In that case your directive's controller overrite ng-controller functionality.
So leave 'ng-controller',
if you need any functionality in your directive
then pass those functionality using =,&,#-->
<acco ng-controller="SearchMasterController"></acco>

How do I ignore parts of the URL?

Currently I have a local server running with my main page at localhost
I ideally want the setup where the url has a key that I send off to my database to get data and the main page loads that data
For example, someone enters the url of localhost/4962 then 4962 gets sent off to the database, while localhost loads. I am using angularJS so I do have a way of getting the url by doing...
var module = angular.module('app', []).run(function($rootScope, $location) {
$rootScope.location = $location;
});
Then location.absUrl() gets me the complete URL.
But obviously there is no page at localhost/4962, so i just get a 404.
How do i ignore the numbers in the url? Also how do I get just the numbers, I would be willing to do localhost/#/4962 if a hash would simplify matters.
EDIT:
Below are some useful answers. Here is what I went with -
var app = angular.module("app", ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when('/:message',
{
template: " ",
controller: "AppCtrl"
}).otherwise({redirectTo: '/'});
});
app.controller("AppCtrl", function($scope, $routeParams) {
$scope.model = {
message: $routeParams.message
}
//debugging
console.log($scope.model.message)
});
I needed to have
<ng-view></ng-view>
in the index.html.
Angularjs using $routeProvider without ng-view has a way of avoiding the addition of ng-view. Will try that next.
Do it like this:
angular.module('app', ['ngRoute']).config(function($routeProvider, $locationProvider){
$routeProvider.when('/:number?', {
controller: 'homeCtrl',
templateUrl: '/home.html'
});
$locationProvider.html5Mode(true);
}).run(function(){
...
});
In this case, number is optional route paramerer (because it has ? at the end). Then you can get number from controller:
angular.module('app').controller('homeCtrl', function($routeParams){
var number = $routeParams.number;
});
Don't forget to include angular-route.js file ;)
You can use the $location.path()-Function, should return just the path (without hashtag).

Is it good to have main controller in Angular?

I dont know if this is a good practice... I have a controller defined in route config but because my HomeCtrl is in ng-if statement he cannot listen for loginSuccess so I made MainCtrl which listens for loginSuccess and reacts appropriately. This code works just fine but this smells like a hack to me. Should I remove MainCtrl and make it a service? If so some example would be really great.
Index.html
<body ng-app="myApp" ng-controller="MainCtrl">
<div ng-if="!isLoged()">
<signIn></signIn>
</div>
<div ng-if="isLoged()">
<div class="header">
<div class="nav">
<ul>
<li class="book">navItem</li>
</ul>
</div>
</div>
<div class="container" ng-view=""></div>
</div>
</body>
App.js
angular.module('myApp', [])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'HomeCtrl'
})
.otherwise({
redirectTo: '/'
});
})
.controller('MainCtrl', function ($scope) {
$scope.user = false;
$scope.isLoged = function(){
if($scope.user){
return true;
}else{
return false;
}
}
$scope.$on('event:loginSuccess', function(ev, user) {
$scope.user = user;
$scope.$apply();
});
})
.controller('HomeCtrl', function ($scope, $location) {
//this is home controller
})
.directive('signIn', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
//go to the server and then call signinCallback();
}
};
})
.run(['$window','$rootScope','$log',function($window, $rootScope){
$window.signinCallback = function (res) {
if(res){
$rootScope.$broadcast('event:loginSuccess', res);
}
else{
$rootScope.$broadcast('loginFailure',res);
}
};
}]);
I start all of my Angular projects with:
<html ng-app="appName" ng-controller="appNameCtrl">
The use of a "global" controller may not be necessary, but it is always nice to have it around when a need arises. For example, I use it in my CMS to set a binding that initiates the loading of everything else - so all the sub controllers are loaded because of it. That isn't violating separation of concerns because the global controller's concern IS to facilitate the loading of other controllers.
That said, just be sure to keep things as modular/separated and reusable as possible. If your controllers rely on the global controller's existence in order to function, then there is an issue.
In my opinion angular js' power comes with separating out clearly the different controllers directives, services, resources etc. Ideally controllers are linked to templates or partials and are used to update the front end and make calls to services or resources. The sooner you start making these separations the sooner you will start making clean and scalable apps that other developers can quickly make sense of. For app structure I would highly recommend you look into either of these two tools:
Lineman.js
and
Yeomann
The lineman site actually has a really good round up of how the two differ, if you scroll down.
In your scenario there are many ways to link controllers or make function calls that are in different scopes. You can either create a service that injects to your controllers or you can use $emit and $on to set up notifications in the app eg:
In controller A
$rootScope.$on('myNotifier:call', function() {
myFunction();
});
And in Controller B or any other controller you could call myFunction() with:
$scope.$emit('newPatientModal:close');

Categories

Resources