angular 1.3 can't find the controller function - javascript

I am new to angular and tried to go with 1.3 new release.
Here is my code
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.0/angular.min.js"></script>
</head>
<body>
<div data-ng-controller="SimpleController" >
<ul>
<li data-ng-repeat="customer in customers">{{customer.name}} - {{customer.city}}</li>
</ul>
</div>
<script>
function SimpleController($scope){
alert('done1');
$scope.customers=[{name:'1name',city:'1city'},{name:'2name',city:'2city'}];
alert('done');
}
</script>
The console gives this error.
Error: [ng:areq] http://errors.angularjs.org/1.3.0-rc.0/ng/areq?p0=SimpleController&p1=not%20a%20function%2C%20got%20undefined
But when I change the angular source to
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
Then it works. I use chrome.
any one let me know where can be the problem exists.

Global controller functions are no longer supported by default in 1.3. See change log...
$controller will no longer look for controllers on window. The old
behavior of looking on window for controllers was originally intended
for use in examples, demos, and toy apps. We found that allowing
global controller functions encouraged poor practices, so we resolved
to disable this behavior by default.
It can be re-enabled with this config...
angular.module('myModule').config(['$controllerProvider', function($controllerProvider) {
// this option might be handy for migrating old apps, but please don't use it
// in new ones!
$controllerProvider.allowGlobals();
}]);

Related

How does childscope work on an ng-if statement? Specifically in a <SELECT> element

NOTE: I'm a new member here so I couldn't directly comment and ask for clarification.
So, my question is: How can I work around ng-if creating a child scope for a select element?
I have the following code:
HTML
<select id="project-select"
ng-if="projects.length > 0"
ng-options="project.name for project in projects"
ng-model="currentProject"
ng-change="broadcastChange('project-changed', currentProject)">
</select>
And my controller is set up in the following format:
function Controller() {
//Do code stuffz
}
angular
.module('app')
.controller('Controller', Controller);
I learned from this post that the "ng-if" is creating a child scope.
So even when the model changes, this part stays the same because it is a primitive value: (name is just a string)
<div id="current-project" class="pull-left">
<strong>Project: </strong>{{currentProject.name}}
</div>
Furthermore in the aforementioned post there were a couple options.
a. Simply change to this: ng-model="$parent.currentProject" which feels a little hacky
b. Set the object value in the controller, which I'm not entirely sure how to do. I feel like it's an easy fix, but I'm somehow overcomplicating it.
Anyway, for now I simply changed ng-if to ng-show and that's solved the problem. However, I am trying to understand Angular more deeply and I feel like this issue could be explained a little bit better to me. Thanks in advance!
What you will find with Angular scope variables is: always use a dot.
That's the mantra from the excellent ng-book
In your case, what this means is this:
You have this code:
<select id="project-select"
ng-if="projects.length > 0"
ng-options="project.name for project in projects"
ng-model="currentProject"
ng-change="broadcastChange('project-changed', currentProject)">
</select>
Which means that you are binding to a $scope variable called $scope.currentProject.
Because of the mysterious and awesome way that javascript works, this does not get updated when you are inside of a child scope.
Thankfully, the solution is actually quite simple. Instead, create an object like so:
$scope.myData = {
currentProject: ''
}
And in your markup, bind to that like so:
<select id="project-select"
ng-if="projects.length > 0"
ng-options="project.name for project in projects"
ng-model="myData.currentProject"
ng-change="broadcastChange('project-changed', myData.currentProject)">
</select>
And voila. It will update, even though it's in a child scope.
This is actually quite useful, because you now have a way to "meaningfully" group variables together. Here's some other pseudo-code to demonstrate what I mean:
$scope.projectData = {
currentProjectID: 1,
currentProjectTitle: 'My Cool Project',
projects: [
{id: 1, name: 'My Cool Project'},
{id: 2, name: 'Another Project'}
],
someOtherProperty: false
// ...etc....
}
As a side-note, this section of this article might be helpful: http://docstore.mik.ua/orelly/webprog/jscript/ch11_02.htm#jscript4-CHP-11-SECT-2.1
If all you want to do is show/hide the select element based on the projects in your 'Controller' controller scope, then ng-show is the right way to go here. In my experience, I've used ng-if when I'm conditionally loading a larger "partial" view containing numerous controls where I felt a separate scope was necessary to avoid having a very large scope (or to facilitate re-use).
You are correct. Do not use $parent in any production Angular apps. It makes your model dependent on the structure of your view, which makes your code hard to refactor and less modularized.
Binding to object properties is the way to go, as you suggested in your "b" answer. The recommended way to do this in the latest version of Angular 1.x is by using the "controller as" syntax. This method makes use of "prototypical inheritance" in javascript. There is a good explanation on this here: http://javascript.info/tutorial/inheritance
I created a plunker for you to demonstrate how binding to object properties works in nested scopes. take a look at the "controller as" syntax". also, try changing the value of ctrl.testBinding in the input, you will see that reflected in the ng-if child scope. I will try to find some links to explain this in more detail.
https://plnkr.co/edit/Gx5xbkJXgzjPSG8kajPR?p=preview
<!DOCTYPE html>
<html >
<head>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="testApp">
<div ng-controller="testCtrl as ctrl">
<input ng-model="ctrl.testBinding" type="text"/>
<button ng-click="ctrl.toggle()">toggle show</button>
<div ng-if="ctrl.show">
{{ ctrl.testBinding }}
</div>
</div>
</body>
</html>
//script.js
function testController($scope) {
var vm = this;
vm.show = true;
vm.toggle = function(){
vm.show = !vm.show
}
}
angular
.module('testApp', [])
.controller('testCtrl', testController);

converting Jquery to angular or making Jquery work in angular

I am new to angular and we are converting a set of screens based on jsp to angular. Initially we have written lot of code in Jquery. Converting them to angular is tedious task and thought of trying to see if we can make jquery work with angular. Here is teh code snippet that i am trying to make it work while it in Jquery.
$(document).ready(function() {
$("#ClickTask2").click(function() {
$(".ClickTask1").hide();
$(".ClickTask2").show();
});
});
Above is the piece of code I have in JQuery and i tried to make it work.
angular.element(document).ready(function() {
$("#ClickTask2").click(function() {
$(".ClickTask1").hide();
$(".ClickTask2").show();
});
});
Can anyone tell me how i could make it work with minimal changes to the above one and rest of the jqueries?
You can convert many jquery features over to Angular by simply changing the $() method to angular.element() e.g.
$('#output').html('<h1>Title</h1>');
You could convert this to:
angular.element('#output').html('<h1>Title</h1>');
However not all function work, and some are renamed e.g.
$("#output").click(function() { console.log('Hi'); });
Would need to be changed to:
angular.element('#output').on('click', function() { console.log('Hi'); });
You can find a full list of the supported functions here:
https://docs.angularjs.org/api/ng/function/angular.element
like said Luis Masuelli on the comments read the basis of Angular. a quick lesson
app.js
function TaskCtrl($scope) {
$scope.selectedTask = null;
$scope.tasks = [/* ... */];
$scope.onClickTask = function(task) {
$scope.selectedTask = task;
}
$scope.isSelected = function (task) {
return task === $scope.seletectedTask;
}
}
$scope it is a special variable, it is injected by Angular to controllers and serves to communicate the controller with the view among other things. A controller can be any function and the name does not matter.
main HTML
<ul data-ng-controller="TaskCtrl">
<li data-ng-repeat="task in tasks" data-ng-click="onClickTask(task)">
{{task.title}}
<div data-ng-show="isSelected(task)">{{task.description}}</div>
</li>
</ul>
data-ng-controller tells to Angular "this is the controller" for this tag and her children. The other directives are pretty explanatory, but the documentation you left it more clearly.
Of course I am assuming that your tasks has the following structure:
{
title: "...",
description: "..."
}
in your html you need include the angular.js, the previous js and a directive to tell angular that this is a application
<!DOCTYPE html>
<html>
<head></head>
<body data-ng-app>
<!-- main HTML -->
<script src="angular.js"><script/>
<script src="app.js"><script/>
</body>
</html>
the data- prefix on each directive is not necessary but as angular "extend" HTML and these are not native attributes, I use them to place custom attributes as "ng-repeat", "ng-controller", "ng-app" etc. They are called directives
Remember, with Angular you need not manipulate the DOM directly as is done with jQuery, except for some special exceptions

AngularJS - Difference between creating controllers

I am new to AngularJS. When i am creating a controller, I have seen two examples which show how to do it differently. How ever the one that most show is the way to do it doesnt work.
The issue with the first one, is that it either can't find the module, or it cant find the function. And it ends up just as {{type}} {{name}}. How ever if i try on plnkr then the first one works.
'dataControl' is not a function, got undefined
Is the error i am getting
If i have my html as this.
<html ng-app>
<head>
</head>
<body ng-app="docsBindExample">
<script src="../bower_components/angular/angular.min.js"> </script>
<script src="../scripts/controllers/main.js"></script>
<div ng-controller="dataControl">
<select id="selected" ng-model="type">
<option>Total Revenue</option>
<option>Total Expenditure</option>
<option>Total Number of Events</option>
<option>Amount of Mail</option>
<option>Average Delivery Times</option>
<option>Critical Routes</option>
</select>
{{type}}
{{data}}
<ul>
<li ng-repeat="values in data">
{{values.dataName}}
{{values.dataValue}}
</li>
</ul>
</div>
</body>
</html>
And then the first controller, that doesnt work.
angular.module('docsBindExample', [])
.controller('dataControl', ['$scope', function($scope) {
$scope.name = 'Value Is here';
}]);
Secondly, the other controller that does work
function dataControl ($scope) {
$scope.name = 'Value Is here';
}
Is there any draw back from using the second ?
There is no any such drawback using the second approach. However the first approach is quite convenient one for the big applications as you will be defining your modules and registering controllers, filters etc against your modules. The reason behind your first approach is not working is may be you have not defined docsBindExample module. Trying doing this:
var docsBindExample = angular.module('docsBindExample', []);
and then your controller definition.
Try using the following
Working Demo
html
<div ng-app="docsBindExample">
<div ng-controller="dataControl">
<select id="selected" ng-model="type">
<option>Total Revenue</option>
<option>Total Expenditure</option>
<option>Total Number of Events</option>
<option>Amount of Mail</option>
<option>Average Delivery Times</option>
<option>Critical Routes</option>
</select>
{{type}}
{{data}}
<ul>
<li ng-repeat="values in data">
{{values.dataName}}
{{values.dataValue}}
</li>
</ul>
</div>
</div>
script
var app = angular.module('docsBindExample', []);
app.controller('dataControl', function ($scope) {
$scope.name = 'Value Is here';
});
Syntactically both works perfect but the first approach is recommended than the second one. In first approach the controller will be attached to that module and is been a good practice for building an application.
For more details visit this link
https://docs.angularjs.org/guide/controller
And there is no error when I executed your code.
Your code is working for me!!!!
Check: http://plnkr.co/edit/hrkSDOinTcMEmPLcttut
Maybe this links from Stackoveflow works for you!!!
AngularJS - different ways to create controllers and services, why?
Globally defined AngularJS controllers and encapsulation
The first is definitely the recommended way (if nothing else because it does to polute the global object).
I haven't tried it myself, but I am pretty sure you are going to run into trouble when your application becomes more complex (with more than 1 modules and/or external dependencies).
The error you get is probably due to some JS error (e.g. a syntax error) which csuses the dataControl to fail registering as a controller.
Unfortunately, such errors are annoyingly undescriptive and hard to track down.
I suggest commenting out all the code inside the controller definition and then uncomment block by nlock until you find the problematic line.
For me, more than a few times, such errors where caused by a wrong object declaration:
E.g. {prop = val} instead of {prop: val} or {p1:v1; p2:v2} instead of {p1:v1, p2:v2}
try changing it to:
.controller('dataControl', function($scope) {
//more code
});

Dynamically load modules angular

I'm looking for a way to load a module (js, css and html) with just one directive anytime during the app life.
<my-module id="contacts"></my-module>
And the template of this directive generates
<my-module id="contacts">
<link type="stylesheet" href="modules/contacts/contacts.css">
<script type="text/javascript" src="modules/contacts/contacts.js"></script>
<ng-include src="modules/contacts/contacts.html"></ng-include>
</my-module>
And the .js file creates a new angular module
// modules/contacts/contacts.js
angular.module('my-contacts', [])
.controller(ContactsCtrl, function($scope) { ... });
And the '.html' uses a controller in this module
// modules/contacts/contacts.html
<ul ng-controller="ContactsCtrl">
<li ng-repeat="contact in contacts">{{ contact.name }}</li>
</ul>
It wont work because the page's module <html ng-app="my-app"> does not depends on my-contacts module. So I would like every module to inject itself as a my-app dependency.
I've found every module (object returned by angular.module) contains a requires array with it's dependencies. I've injected my-contacts into that array and this works:
// modules/contacts/contacts.js
angular.module('my-app').requires.push('my-contacts');
angular.module('my-contacts', [])
.controller(ContactsCtrl, function($scope) { ... });
But I can't find this property on the documentation. Is it standard or it can change anytime? anyone knows?
Update
To be clear, this is not to load a single module with a single component, this is meant to load a entire application, imagine it like a launcher (like MacOS dockbar or Ubuntu's unity sidebar) with dynamically added icons and when one of this icons are clicked it should run the module. But I don't know at the webpage start which apps this launcher should be able to launch and I need to add more applications dynamically. As each app can has it's own directives and services I use angular modules as apps.
<body ng-app="my-app">
<ul>
<li ng-repeat="module in modules">
<button ng-click="selectedApp = module.id">{{ module.name }}</button>
</li>
</ul>
<my-module id="{{ selectedApp }}"></my-module>
</body>
I'm not sure you're trying to abstract the code so much.
What you should be able to do:
Make a module
Put a directive in the module with your contacts list
Inject the module into your page. And use the contact list.
Dependencies are usually the second argument of a module definition. i.e:
angular.module('my-app', ['my-contacts']);
Is this what you were referring to? The dependencies and how to inject them correctly?

In AngularJS 1.2, how do I specify the controller for an ng-include?

We are attempting to upgrade from AngularJS 1.0.7 to 1.2.1. In 1.0.7, we were able to set the controller for an ng-include alongside in the same element, like so
<div data-ng-include="'include1.html'" data-ng-controller="MyCtrl1"
MyCtrl1 would become available to the code inside include1.html.
This breaks when moving to AngularJS 1.2.1 which I have illustrated in this plunkr. If you change the referenced version to 1.0.7 it works again.
I am interested in understanding what has changed/why this is. I tried searching but couldn't find anything or I am not using the right terms.
Additionally, what would be the correct way to specify a controller for my ng-includes?
Why not move the ng-controller from the element having ng-include to inside the template:
index.html:
<div data-ng-include="'include1.html'"></div>
<div data-ng-include="'include2.html'"></div>
include1.html
<div data-ng-controller="MyCtrl1">
<h1>{{Username}}</h1>
</div>
include2.html
<div data-ng-controller="MyCtrl2">
<h1>{{Username}}</h1>
</div>
It seems ngController and ngInclude cannot be used in conjunction with each other since Angular version 1.2:
Issue 1, Issue 2, Issue 3 and SO post.

Categories

Resources