AngularJS Controller syntax with as - angularjs

I am using AngularJS 1.6.9 with AngularJS Material. What I want to do is to add a menu item basic usage. The problem is that it didn't work because my structure is different.
Documentation of material says (I never seen it before):
angular
.module('menuDemoBasic', ['ngMaterial'])
.config(function($mdIconProvider) {
$mdIconProvider
.iconSet("call", 'img/icons/sets/communication-icons.svg', 24)
.iconSet("social", 'img/icons/sets/social-icons.svg', 24);
})
.controller('BasicDemoCtrl', function DemoCtrl($mdDialog) {
...
Html:
<div class="md-menu-demo" ng-controller="BasicDemoCtrl as ctrl" ng-cloak>
...
My controller's name is MainController and I don't want to change my syntax.
My js syntax is:
app.controller("MainController", ["$scope","$http","$rootScope", function($scope,$http,$rootScope){
...
How can I change the code, in order to not to change my structure of my Controller and play?

Include $mdDialog like
app.controller("MainController", ["$scope","$http","$rootScope", "$mdDialog", function($scope,$http,$rootScope, $mdDialog){
... // order should be same.
And HTML
<div class="md-menu-demo" ng-controller="MainController" ng-cloak>
...

Related

Directive not working in angularjs

I am newbie to Angularjs. I am trying to create simple directive with the following code:
View:
<html>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<user-info></user-info>
</div>
</body>
</html>
Controller:
myapp = angular.module("myapp", []);
myapp.directive('userInfo', function() {
var directive = {};
directive.restrict = 'E'; /* restrict this directive to elements */
directive.template = "My first directive: ";
return directive;
});
I am following this Tutorial to learn directive
http://tutorials.jenkov.com/angularjs/custom-directives.html
I am getting error:
http://errors.angularjs.org/1.3.14/$injector/modulerr?p0=myApp&p1=Error%3A%20%5B%24injector%3Anomod%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.3.14%2F%24injector%2Fnomod%3Fp0%3DmyApp%0A%20%20%20%20at%20Error%20(native)%0A%20%20%20%20at%20http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A6%3A417%0A%20%20%20%20at%20http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A21%3A412%0A%20%20%20%20at%20a%20(http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A21%3A53)%0A%20%20%20%20at%20w.bootstrap%20(http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A21%3A296)%0A%20%20%20%20at%20http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A35%3A46%0A%20%20%20%20at%20s%20(http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A7%3A302)%0A%20%20%20%20at%20g%20(http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A34%3A399)%0A%20%20%20%20at%20ab%20(http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A38%3A135)%0A%20%20%20%20at%20d%20(http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.14%2Fangular.min.js%3A17%3A381
Here is my codepen link
http://codepen.io/anon/pen/NGNKxz
You have error in the name of your app :
myapp = angular.module("myApp", []); // not 'myapp'
Add Your Directive
You need to add the directive to your html like so
<script src="path/to/your/directive.js"></script>
or if your working from one module you will link to the main module. But please restructure your app like this it will keep code up to standard and clean.
I have a git hub repo where I am building an app in this structure here. Best of luck.
Note
You are using angular min. Min is great for production because its small and faster to load but your in development at the moment so use the full version so you can capture errors better with the browser console.
Looks like you did not declare the controller myCtrl. Your directive looks fine.
myapp.controller('myCtrl', function() {
});
Is it the current version of your html file ?
Because you might need to link your controller, between head tags, insert :
<script src="the js file which contains your controller"></script>
or
<script>Your controller</script>

ng-include and ngRoute: how to make them work together? (i.e. route to a view wihin a ng-include)

[EDITED] My app has the following structure:
index.html
<body ng-app = "myApp" ng-controller ="mainController">
<ng-view></ng-view>
</body>
mainView.html (loaded into ng-view through routeProvider in app.js)
<div ng-include src="subview1">
<div ng-include src="subview2">
subview1 and subview2 are set within mainController (mainView's controller) as scope variables:
$scope.subview1= "templates/subview1.html";
$scope.subview2= "templates/subview2.html";
controller1 and controller2 are subview1 and subview2's controllers.
subview1.html (loaded in first div of mainView)
<div ng-controller="controller1">
<button ng-click="loadNewView()"></button>
</div>
controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$scope.$parent.subview1 = "templates/view3.html";
}
}
scope.loadNewView should load a different view (and relative controller) within the div with src="subview1" in mainView.html). Basically it's about refreshing the view itself by raplacing it with another view (and related controller).
I use $parent to update the view in subview1's parent view (i.e. mainView).
however nothing happens and if I try to use $scope.$apply() I get error (digest already in progress).
Any clue?
you can try something like this...
In your stateProvider or in your routeProvider if you using.
var mod = angular.module('example.states', ['ui.router']);
mod.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('exampleState', {
url: '/main',
templateUrl: 'mainView.html',
controller: mainController
});
}
]);
return mod;
So here you have associated your parent controller(let's say the mainController which will be the parent of all others) with its template mainView.html.
Then in your mainView.html,Load all the subview templates.
<div ng-repeat="template in templates">
<ng-include src="template.url"></ng-include>
</div>
templates is an array in your mainController which has the url or path of all your subtemplates.When you use ng-include inside the main template then all subTemplates will automaticlly become the child of the mainTemplate and its Controllers too.In a way it will inherit from the parent Controller.
So suppose if subView1.html is one of the template url you had given in ng-include.Then it will look like
<div ng-controller="subView1Controller">
//Here your code
</div>
And subview2 as
<div ng-controller="subView2Controller">
//Here your code
</div>
This way you will have multiple views on the same page with one url and different controllers with its associated templates and each will inherit from the parent controller which is mainController here.
There, might be better approach than this.
This is what i had used in my project,and its simple to keep your code simple manage.
Okay,so using routeProvider,you can use it like this
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
});
app.controller("mainController",function($scope){
});
app.controller("subView1Controller",function($scope){
});
app.controller("subView1Controller",function($scope){
});
Then in your mainView.html,Load all the subview templates.
<ng-include src="yoursubtemplate1path"></ng-include>
<ng-include src="yoursubtemplate2path"></ng-include>
And then in yoursubtemplate1 use
<div ng-controller="subView1Controller">
//Here your code
</div>
Same for the other templates.
You can set the template src of the subtemplates from your mainController.
app.controller("mainController",function($scope){
$scope.templatesrc="/app/template1.html";
});
And then use it in your template,where you are using ng-include directive.
<ng-include src="templatesrc"></ng-include>
Its better to store template url's in an array and use ng-repeat directive like i had stated before,if you are loading more templates.
And if you want to show the div on some button click lets say in parent controller then use ng-if in the sub-view main and make it true on button click.
This answer is regarding your updated question.
The solution which you had used before,will load all temlplate and once in ng-include and its associated controller making the mainController as parent.
But if you want to load a different view with its newController then you can try something like this.
Just add one more route and call on your event click,but remember this newView's Controller will have no parent-child relation with the mainView's controller.
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
.when('/anyName',{
templateUrl:"templates/view3.html",
controller:temp3Controller
})
});
And in your controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$location.path('/anyName');
}
}
Inject location service in controller1.
I finally found the solution.
The tricks is using
$scope.$parent.$parent.subview1 = "templates/view3.html";
instead of
$scope.$parent.subview1 = "templates/view3.html";
since, basically:
ng-include is the child of mainView
subview1 is the child of ng-include

Using angular includes like mvc partials

Consider the following:
<script type="text/ng-template" id="myTemplateName">
{{item.SomeProperty}}
<script>
<div ng-repeat="container in List">
<div ng-repeat="item in container.Items">
<!-- CASE 1 -->
<div ng-include="'myTemplateName'"></div>
</div>
<!-- CASE 2 -->
<div ng-include="'myTemplateName'" />
</div>
The code above works in case1, but not in case2: case 1 will work because the template uses item, which is made available by the ng-repeat statement outside of the template, case 2 doesn't work because there is no item, instead i want it to use container.SomeProperty.
Maybe i am misusing angular includes, but i wanted to use them like partials in ASP.Net MVC. There, you can define a partial and you are able to pass in a model.
Is there any way in angular that allows me to set what item means inside the template?
Problem solved using Matt's answer:
module.controller("ItemController", ['$scope', function ($scope) {
$scope.templateitem = ($scope.$parent.item) ? $scope.$parent.item : $scope.$parent.$parent.container.Item;
}]);
Still, it feels kind of dirty: the controller needs to know how it can be used. It would be better if i could pass this to the controller from the outside.
A better approach:
I didnt really like the solution above, because the controller needs to know how it will be used, so i used a directive:
app.directive("opportunity", function () {
return {
restrict: "E",
templateUrl: "opportunityTemplate",
scope: { templateitem: "=model" }
};
});
In view:
<script type="text/ng-template" id="opportunityTemplate">
{{templateitem.SomeProperty}}
</script>
<opportunity model="container.Item"></opportunity>
<opportunity model="somethingElse.Item"></opportunity>
Now all i need to find out is how i can pass the templatename into the directive, and i can make a re-usable "partial" directive (please tell me if i am reinventing the wheel here?)
What you need to use is ng-controller, or some routing system like ui-router that connects partials to controllers through route definitions.
For the first example, when you add your partial, also specify a controller which takes care of dealing with the model:
HTML:
<div ng-controller="MyCtrl" ng-include="'myTemplateName'" />
<!-- inside the template -->
<div>{{item.somekey}}</div>
Controller:
angular.module('myapp.ctrl', [])
.controller('MyCtrl', ['$scope', function($scope){
$scope.item = { somekey: 'somevalue' };
}]);
In the second example, use a routing system like ui-router. An example of that can be seen here, where certain partials are attached to controllers and specific urls:
https://github.com/angular-ui/ui-router/tree/gh-pages/sample

Best way of loading and destroying in angular JS 1.2

I have a scenario where I need to dynamically load an Angular JS application. I have based the code on this:-
https://stackoverflow.com/a/15252490/1545858
Now, I have code that works really well with angular js 1.1.5, but in 1.2.1, no such luck.
Here is the JS code:-
$("#startMeUp").click(function() {
// Make module Foo
angular.module('Foo', []);
// Make controller Ctrl in module Foo
angular.module('Foo').controller('Ctrl', function($scope) {
$scope.data = {};
$scope.data.name = 'KDawg';
$scope.destroy = function() {
$scope.$destroy();
$('#Ctrl').remove();
};
$scope.$on("$destroy", function () {
console.log("EXTERMINATE");
});
});
// Load an element that uses controller Ctrl
$('<div ng-controller="Ctrl" id="Ctrl"> ' +
'<input type="text" ng-model="data.name"></input>' +
'{{data.name}}' +
'<button ng-click="destroy()">Destroy Me</button></div>').appendTo('#container');
// Bootstrap with Foo
angular.bootstrap($('#Foo'), ['Foo']);
});
And here is the HTML:-
<button id="startMeUp">Start Me Up!</button>
<div id="Foo">
<div id="container">
</div>
</div>
Now, if you start and destroy and start again with angular js 1.1.5, everything works fine, but in angular js 1.2.1 it does not work in on the second start. Any thought on how to make it work in 1.2.1?
Here is the js fiddle:-
http://jsfiddle.net/Y9wj2/
As charlietfl says, you don't need to bootstrap more than once. In fact, using angular.js 1.2.1, the error generated that breaks everything is telling you exactly that:
[ng:btstrpd] App Already Bootstrapped with this Element ''
You should think carefully about whether you really need this controller to be dynamic. If you can just use something like ng-include to load the extra content then you will have a much easier time and no need to worry about compiling the content.
If you find you really do need to take this HTML and load it from outside of angular context then you can use the $compile service. Bootstrap the app once somewhere first, preferably using ng-app and grab the injector.
var injector = angular.bootstrap($('#Foo'), ['Foo']);
or
<div id="Foo" ng-app="Foo"></div>
var injector = $('#Foo').injector();
Now you can insert the HTML however you like and then compile and link it using
injector.invoke(['$compile', '$rootScope', function($compile, $rootScope) {
$compile(insertedJqLiteNode)($rootScope);
});

How to include one partial into other without creating a new scope?

I've this routes.
// index.html
<div ng-controller="mainCtrl">
<a href='#/one'>One</a>
<a href='#/two'>Two</a>
</div>​​​​​​​​​
<div ng-view></div>
And this is how I'm loading the partials into my ng-view.
// app.js
​var App = angular.module('app', []);​​​​​​​
App.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/one', {template: 'partials/one.html', controller: App.oneCtrl});
$routeProvider.when('/two', {template: 'partials/two.html', controller: App.twoCtrl});
}]);
When I click the links, it shows me the appropriate markup inside the ng-view. But when I try to include partials/two.html inside partials/one.html using ng-include, it shows it properly but creates a different scope so I'm not able to interact with it.
// partials/two.html - markup
<div ng-controller="twoCtrl">I'm a heading of Two</div>
// partials/one.html - markup
<div ng-controller="oneCtrl">I'm a heading of One</div>
<div ng-include src="'partials/two.html'"></div>
​
How do I resolve this problem? Or Is there any other way to achieve the same result?
You can write your own include directive that does not create a new scope. For example:
MyDirectives.directive('staticInclude', function($http, $templateCache, $compile) {
return function(scope, element, attrs) {
var templatePath = attrs.staticInclude;
$http.get(templatePath, { cache: $templateCache }).success(function(response) {
var contents = element.html(response).contents();
$compile(contents)(scope);
});
};
});
You can use this like:
<div static-include="my/file.html"></div>
The documentation for ngInclude states "This directive creates new scope." so this is by design.
Depending on the type of interaction you are looking for you may want to take a look at this post for one way to share data/functionality between the two controllers via a custom service.
So this isn't an answer to this question but i made it here looking for something similar and hopefully this will help others.
This directive will include a partial without creating a new scope. For an example you can create a form in the partial and control that form from the parent controller.
Here is a link to the Repo that i created for it.
good luck :-)
-James Harrington
You can actually do this without using a shared service. $scope.$emit(...) can dispatch events to the $rootScope, which can listen for them and rebroadcast to the child scopes.
Demo: http://jsfiddle.net/VxafF/
Reference:
http://www.youtube.com/watch?v=1OALSkJGsRw (see the first comment)

Resources