Angular Controller showing $ is not a function error in Dynamic Routing - angularjs

I am trying to create an Angular Dynamic Routing. My routing is like this:
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives']).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', { templateUrl: 'partials/blank.html' });
$routeProvider.when('/:name', { templateUrl: 'partials/blank.html', controller: PagesController });
$routeProvider.otherwise({redirectTo: '/'});
}]);
Here I am using $http to get a template file inside a controller and compile it to a div id like this:
function PagesController($scope, $http, $route, $routeParams, $compile) {
$route.current.templateUrl = 'partials/' + $routeParams.name + ".html";
$http.get($route.current.templateUrl).then(function (msg) {
$('#view-template').html($compile(msg.data)($scope));
});
}
In the template view, I have a div like this:
<div id="view-template" ng-view></div>
I thought the above code will compile and add the html data to the div but I am receiving the error that says: $ is not a function. What have I got wrong here?
EDIT: After the help from the comments and answers below
SOLUTION:: I was playing around with this a bit more and I went with another solution for this. I added the $route.current.templateUrl to the $scope.theTemplateUrl and then used ng-include in the template file. That did the trick and I also dont need to use the jquery $ function to manipulate the DOM.

Please make a fiddle. The limited scope of this snippet inhibits help :)
By just looking at what you are doing I can only make a few recommendations. But I think your issue lies in .html().
Stop using jQuery while you learn Angular.
Use $scope to change content on page. Instead of
$('#view-template').html($compile(msg.data)($scope));
do this
$scope.viewTemplate = msg.data
then use angular in your view :)
Only use the controller to coordinate the flow of information. There should not be and DOM manipulation happening here. The DOM should reflect a state of the controller.
Define routes in your app config. This is not correct.
$route.current.templateUrl = 'partials/' + $routeParams.name + ".html";
I have some example site in my github repo that you can look at if you want to see a few full sites working: https://github.com/breck421
It seems like you have missed some key parts of Angular. Make sure you take your time and learn it right. It will make you life much easier later.
Thanks,
Jordan
Added for a route provider example:
MyApp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'js/views/index.html',
controller: 'AppController',
activeTab: 'home'
})
.when('/home', {
templateUrl: 'js/views/index.html',
controller: 'AppController',
activeTab: 'home'
})
.when('/thing1', {
templateUrl: 'js/views/thing1.html',
controller: 'Thing1Controller',
activeTab: 'thing1'
})
.otherwise({redirectTo: 'home'});
}]);
Then use links like this: Components
EDIT Adding a compile directive per request:
angular.module('CC.directive.Compile', [], function($compileProvider) {
$compileProvider.directive('compile', ['$compile', function($compile) {
// directive factory creates a link function
return function(scope, element, attrs) {
scope.$watch(
function(scope) {
return scope.$eval(attrs.compile);
},
function(value) {
element.html(value);
$compile(element.contents())(scope);
}
);
};
}]);
});

The $ function is defined by jQuery, not angular. Make sure that you have included the jQuery library in order to use $

Related

AngularJS 1.6.7 controller breakdown and refactor into components

i'm having angularJS app where all controllers are in one file , i want break it down and seperate each controler then refactor it to component based as it's recommended for angularJS 1.5 and above. my current structure looks like this:
.controller('HomeController', ['$scope', function ($scope){
//logic
}
])
and the same for all other controllers are in the same file "controllers.js", in my app.js i do:
var app = angular.module('app', [
'services',
'controllers',
]);
what you advice to break down the controllers into components, thank you for answers and recommendations.
Provided that you are using $scope, you could start by changing from scope to controllerAs syntax, that is, $scope.foo = 'bar' -> <p>{{ foo }}</p> would become this.foo = 'bar' -> <p>{{ ctrl.foo }}</p>.
controllerAs Syntax
From this:
app.controller('HomeController', ['$scope', function ($scope){
$scope.title = 'Home';
}]);
To this:
app.controller('HomeController', [function (){
this.title = 'Home';
}]);
declaring components
Afterward, you'd be able to declare your components in two ways:
Partial refactor using the existing controller:
app.component('homeComponent', {
controller: 'HomeController'
});
Or, full refactor replacing the controller:
app.component('homeComponent', {
controller: [ function (){
this.title = 'Home';
}]
});
refactoring routers
Assuming that you are using ui-router (it's very similar to ngRoute so it wouldn't be a problem).
From this:
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home/home.html',
controller: 'HomeController'
})
To this, for ui-router 1.0+:
$stateProvider
.state('home', {
url: '/',
component: 'homeComponent'
})
Or this, for older versions:
$stateProvider
.state('home', {
url: '/',
template: '<home-component></home-component>'
})
Ref.: Guide: Route to Component
final thoughts
There's a pretty good style guide for angularjs written by John Papa that you should have a look at and use what's worth for you. However, as it's been told by #MikeFeltman it's not accurate with angularjs 1.5 components application style practices; therefore, you should have a look at Todd Motto's revised version of the guide including component application practices.
Disclaimer: I see no point in converting a controller to a directive before making the component, you can declare the component directly because components are special directives and they carry a controller so it's convenient for you.

Error when adding more than one app module

I am using two app modules in this app. Why do I get this error? I define the navCtrl in my index.html file where ng-view is like this:
<body ng-app="ciscoImaDashboardApp" ng-controller="navCtrl">
Error: [ng:areq] Argument 'navCtrl' is not a function, got undefined
What am I doing wrong? Am I getting this because I define angular.module in all my js files?
Routes JS:
angular.module('ciscoImaDashboardApp', ['ciscoImaDashboardAdmin', 'ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/admin', {
templateUrl: 'views/admin.html'
})
.when('/', {
templateUrl: 'views/welcome.html',
controller: 'welcomeCtrl'
})
.when('/overall-results', {
templateUrl: 'views/overall.html',
controller: 'overallCtrl'
})
.when('/swim-lane-results', {
templateUrl: 'views/swim-lane.html',
controller: 'swimlaneCtrl'
})
.when('/key-exemplifiers', {
templateUrl: 'views/key-exemplifiers.html',
controller: 'petalCtrl'
})
});
Second Module:
angular.module('ciscoImaDashboardAdmin',[])
.controller('minisCtrl', function ($scope) {
});
Nav JS:
angular.module('ciscoImaDashboardApp',['ciscoImaDashboardAdmin'])
.controller('navCtrl', function($scope, navService, $location, dummyData) {
});
right way :
angular.module('ciscoImaDashboarAdmin')
.controller('minisCtrl', function ($scope) {
});
remove dependency practice in the second time
from angular js documentation you can find below block check the link here
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.

ngRoute not directing to anything

So I'm trying to learn how to use Angulars routing, following tutorials online, and I can't seem to figure out where I'm going wrong. I have the following code:
var app = angular.module('gamersplane', ['controllers', 'ngCookies', 'ngRoute']);
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/pms/:box?', {
controller: 'pmList'
}).when('/pms', {
controller: 'pmList'
}).otherwise({
controller: 'pmList'
});
}])
var controllers = angular.module('controllers', []);
controllers.controller('pmList', function ($scope, $cookies, $http, $routeParams) {
console.log($routeParams);
});
However, no matter what I do, the controller doesn't get hit. I have otherwise in the router, so isn't that where it should hit if all else fails?
Yes it will hit otherwise but you can only define the redirect path into it and that redirect path will tell the url and the controller to set for the $route.current :-
redirectTo: '/pms'
Doc
You need to add a template to each route:
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/pms/:box?', {
controller: 'pmList',
template: 'test.html'
}).when('/pms', {
controller: 'pmList',
template: 'test.html'
}).otherwise({
controller: 'pmList',
template: 'test.html'
});
}])
squiroids suggestion regarding otherwise was correct, you won't see a change in your test application though.
Routing is meant to be used to navigate between regions of your application. You could have an app with two routes: pms which shows a list of PMs and pms/:box zu view a particular PM Box. The main task for ngRoute is to replace a placeholder in your application (ng-view) with a given template. Without using a template on the individual routes, your $routeProvider will not navigate as expected.
Given you have two views for the regions (pmBox.html and pmList.html), you could configure your $routeProvider zu setup routing like this: https://gist.github.com/kpko/bd0231ccefbaf8c415c7

Moving from individual templates to inline

I am using templateUrl to display specific php pages in my webpage. Now I wish to scrap the individual php pages and display code with variables passed to it. What is the easiest way to get back to this?
var AppModule = angular.module('App', ['ngAnimate', 'ngRoute']);
AppModule.config(function($routeProvider) {
$routeProvider
.when('/page:pageNumber', {
templateUrl: function ($routeParams) {
return '/app/..../assets/html/page' + $routeParams.pageNumber + '.php';
},
controller: "PageCtrl"
})
.otherwise({
redirectTo: "/page1"
});
});
AppModule.controller("ViewCtrl", function($scope, $timeout) {
$scope.$on("$routeChangeSuccess", function(event, current, previous) {
...stuff...
});
});
Use scripts via text/ng-template, which allows you to write your templates inline while declaring a url to access them by. The following code can go directly in your index.html, and if your config is set to show '/my-template.html', the inline template will be output right in the ng-view above it.
<ng-view />
<script type="text/ng-template" id="/my-template.html">
template goes here
</script>
Then in your config:
.when('/', {
templateUrl: '/my-template.html'
});
Here's a little more info from the Angular docs:
https://docs.angularjs.org/api/ng/directive/script
And lastly, this technique is demonstrated in one of the TodoMVC examples for Angular:
View: https://github.com/tastejs/todomvc/blob/gh-pages/examples/angularjs/index.html
Config: https://github.com/tastejs/todomvc/blob/gh-pages/examples/angularjs/js/app.js

duplicate controllers being created by ng-include directive

I'm using the ngInclude directive and defining my own controller
<ng-include
src="'app/streaming/streaming.view.html'"
ng-controller="StreamingCtrl"
ng-if="streamingActive">
</ng-include>
This is defined within main-page.view.html which is the top level page for my app and is listed in app.js as follows:
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'app/common/main-page.view.html',
controller: 'HomeCtrl',
reloadOnSearch:false
})
.when('/multiview', {
templateUrl: 'app/common/main-page.view.html',
controller: 'MultiviewCtrl'
})
}]);
The streaming control is as follows:
app.controller('StreamingCtrl', ['$scope', function($scope) {
console.log($scope);
$scope.$on('destroy', function () {
console.log('destroy');
});
}]);
Everytime I navigate between the home and multiview pages it looks like a new instance of the controller is being created. The scope is logged and each one has a new id but it seems like the destroy method is never call. I think that this is causing a memory leak with new controller instances being created while the old ones are never destroyed.
Any thoughts greatly appreciated
C
This is because you have mispelled the destroy event, it should be $destroy instead of destroy.
DEMO
.controller('StreamCtrl', function($scope) {
console.log($scope);
$scope.$on('$destroy', function () {
console.log('destroy');
});
});

Resources