I'm playing around with Coffeescript and AngularJS, trying to use the new "controller as" syntax. Despite varied attempts and searching Google, I can't get it to work - the controller reference in my html doesn't find the Coffeescript class for the controller.
I suspect I am doing something wrong or just misunderstanding things but if anyone has a working example, it would be very helpful.
Here's a little jsfiddle showing what I am trying to do: http://jsfiddle.net/G2r4p/ (the controller in this example is just an empty dummy controller so I can test the syntax).
When I run this example in my browser I get:
Error: [ng:areq] Argument 'AppController' is not a function, got undefined
at hasOwnPropertyFn (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:60:12)
at assertArg (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:1187:11)
at assertArgFn (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:1197:3)
at $get (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:5547:9)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:5060:34
at forEach (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:203:20)
at nodeLinkFn (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:5047:11)
at compositeLinkFn (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:4607:15)
at compositeLinkFn (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:4610:13)
at publicLinkFn (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.js:4516:30)
Thanks
JS Fiddle is the culprit. Your syntax is correct and works fine as is when I tried it in JS Bin. It looks like JS Fiddle is processing something out of order, compared to JS Bin, which doesn't suffer from this issue.
Check out the working JS Bin example: http://jsbin.com/akABEjI/1/edit
You might also be interested in my blog post that takes the AngularJS Todo app and converts it to CoffeeScript: "Writing AngularJS controllers with CoffeeScript classes." Ultimately your sample is similar to what I end up with in my final example.
I have changed a bit your code and it is working now (http://jsfiddle.net/denisonluz/r5KQb/2/)
Also bear in mind that sometimes can be a bit tricky to make AngularJS work when using JSFiddle. There's a good post here about it. When using AngularJS and CoffeScript on JSFiddle you must use manual bootstrap.
COFFESCRIPT
testApp = angular.module 'testApp', []
testApp.controller 'AppController', ($scope) ->
$scope.items = [{title: "My test App", description: 'Some Text Here'}]
angular.bootstrap document, ["testApp"]
HTML
<div ng-controller='AppController'>
<h3>one plus two is {{1 + 2}}</h3>
<ul ng-repeat='item in items'>
<li>{{item.title}}</li>
<li>{{item.description}}</li>
</ul>
</div>
The problem isn't your CoffeeScript, it's JSFiddle.
The problem is that the way JSFiddle is doing CoffeeScript, it's processing the CS and executing the created JavaScript well after Angular tries to bootstrap the app with your ng-app="TestApp" directive.
While #dluz, "solves" this problem, it doesn't explain it.
One solution is to bootstrap your app manually, as #dluz suggests, but you won't have to, and shouldn't have to, do this in a production environment.
Ideally, in a production environment, you'd be pre-processing your CoffeeScript and it would never be compiled to JavaScript in the browser, as it is in JSFiddle.
Here is a simple example with coffeescript, angular and jade working side by side
doctype html
html(lang="en")
head
meta(charset="utf-8")
title Test
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.js')
script(src='http://coffeescript.org/extras/coffee-script.js')
style.
input { width: 200px }
script(type='text/coffeescript').
app = angular.module('App', [])
app.controller 'TestController', ($scope)->
$scope.name = 'Angular 1.4 with Jade with coffee'
angular.bootstrap document, ["App"]
body
div
div(ng-controller="TestController")
h2 {{name}}
hr
input(type="text" ng-model="name" )
Related
I'm in the middle of the transition from version 1.2.* to 1.3.* , and I came across a very strange and critical bug.
In my application I have a very simple directive contain a template with ng-class (with condition to scope property) for some reason it's not working with 1.3.* version, and it's work fine with 1.2.* version.
Have a look on this Plunker to illustrates the problem.
This Plunker code is with angular 1.2.* version, and as you can see it's work fine.
Try to change the angular version (index.html)
<script src="https://code.angularjs.org/1.3.9/angular.js"></script>
<script src="https://code.angularjs.org/1.3.9/angular-animate.js"></script>
<!--<script src="https://code.angularjs.org/1.2.28/angular.js"></script>
<script src="https://code.angularjs.org/1.2.28/angular-animate.js"></script>-->
Refresh the page, and then you can see the bug:
Angular doesn't refresh the ng-class according to the 'active' property changing.
I tried to understand what can causes to this bug, and after a lot of tries I found that 'ngAnimate' module causes to this problem. try to delete the 'ngAnimate' dependency (script.js):
//var app = angular.module('app', ['ngAnimate']);
var app = angular.module('app', []);
And then you can see that everything is fine, so 'ngAnimate' version 1.3.* causes to this problem.
So it's AngularJS bug, am I right?
If not, what I'm doing wrong?
Do you have any specific reason to use the replace option in the directive? If not, you can just remove it and it works fine. Link to working plunker with Angular 1.3.9:
http://plnkr.co/edit/jLIS9uJ1PHC64q6nEmtB?p=preview
V1.3.9 docs tell that replace is deprecated and very rarely needed for directives to work, and apparently in your case it also managed to cause some trouble.
As per the doc replace will be deprecated in version 2. As you are using Angular 1.3.9, that should be fine.
To fix this issue either you can remove replace from directive or still if you want to use replace then wrap directive template content which has ng-transclude in a div like below
<div><div ng-click='click()' ng-class='{\"{{defaultColorClass}}\" : !active, \"{{activeColorClass}}\": active, \"mousePointer\" : !active}' class='k-content-button-inner-style {{effectClass}} {{externalClass}}' ng-transclude></div></div>
For more info refer - https://docs.angularjs.org/api/ng/directive/ngTransclude , Explain replace=true in Angular Directives (Deprecated).
#bensiu: Removing the unused* variable {{effectClass}} in the template will make it work for 1.4.4 in the plunker example linked to the question.
Modified plunk here
*Edit: Probably I should say "using a variable not in scope" rather than "unused variable".
I'm using angular 1.1.5 with ngInclude in my template. Whenever I load the page I get a duplicate path after the hashbang: http://localhost/home#/home, http://localhost/account#/account, etc. This happens when there's ngInclude directive in the page (I think this also happens with ngView). I'm not using any routing with this app, and it's a very simple setup overall.
Using $locationProvider.html5Mode(true) in the module configuration seems to resolve this, but I don't want to use that as it doesn't really fit with this application's design.
This doesn't seem to happen in angular 1.2.0-RC.2, but I don't want to migrate just yet. Any known workarounds? thanks.
Use a function as the value:
app.controller("foo", function($scope) {
$scope.url = function() {
return "/bar";
}
});
<div ng-controller="foo">
<ng-include src="url()"></ng-include>
</div>
I am trying to experiment with examples and tutorials at http://docs.angularjs.org/guide/expression and the examples are not working in plunker and jsfiddle. I am getting this error in the console
Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.2.0rc1/$injector/modulerr?p0=App&p1=Error%3A%…eapis.com%2Fajax%2Flibs%2Fangularjs%2F1.2.0rc1%2Fangular.min.js%3A27%3A198)
Is this a known error?
JSFiddle in particular has always been difficult to get working with AngularJS. The HTML section isn't meant to take an entire HTML document. Instead, you need to configure the workspace to work with Angular following these steps:
Under external resources, add the Angular script (remember to click the + icon)
Under Fiddle Options change the body tag to include ng-app like so: <body ng-app>
That should get you started. If you don't mind using an older version of Angular (1.1.1), you can select it from the "Frameworks & Extensions" drop down and change the 2nd drop down from onLoad to No wrap - in <body>.
See here for a working example from the docs: http://jsfiddle.net/jPtb3/
And here for the optional approach using 1.1.1: http://jsfiddle.net/5nA2H/
Update
There's some misinformation in the comments.. The docs ARE actually creating angular.module for you, but they're passing in an empty dependency. So you can either remove ="App" (not best), or you fix the angular.module declaration by removing the empty dependency (best) like so:
angular.module('App', []);
I do not truly understand why it is necessary to do an angular.bootsrap document, ['MyApp'] at the end of my CoffeeScript code that manages the module and controllers in the following test application:
This is the HTML:
<div ng-app='InventoryModule' ng-controller='InventoryController'>
<ul ng-repeat='item in items'>
<li>{{item.title}}</li>
<li>{{item.price | currency}}</li>
</ul>
</div>
And the CoffeeScript:
inventoryModule = angular.module 'InventoryModule', []
inventoryModule.factory 'Items', ->
items = {}
items.query = () -> [{title: 'Hello', price: '5'}]
items
inventoryModule.controller 'InventoryController', ($scope, Items) ->
$scope.items = Items.query()
angular.bootstrap document, ["InventoryModule"]
If you remove the last line, the applicatoin won't work. Why is that? This is not truly explained anywhere else.
This is a fiddle of the code:
http://jsfiddle.net/dralexmv/8km8x/11/
As you can see the application actually works. If you remove the bootstrap it will stop working.
Tl;dr
Set the second drop-down in jsFiddle to "No wrap - in <head>" and you won't need angular.bootstrap line.
FIDDLE
Explanation
When Angular library is loaded it will scan the DOM looking for element with ng-app directive. When it finds one it will begin the bootstrapping proces.
In that process Angular will take the value of ng-app attribute (in your case that's InventoryModule) and will try to find an angular module with the same name. If it fails it will throw: Uncaught Error: No module: <module name>.
In your fiddle you have set the "Code Wrap" select box to "onLoad".
This drop-down instructs jsFiddle when to initialize the JS code that you've put in JS frame. When it's set to "onLoad", the code will run in onLoad window event.
On the other hand, Angular bootstrapping process will run on $(document).ready(), and because $().ready event is fired before "onLoad" event, Angular will try to init the InventoryModule module before the module is even defined, and that's where the dreaded "No module" error will be thrown.
angular.bootstrap() is a manual way of doing the same thing that Angular already does in it's $().ready() handler.
Take a look at the error console. Your code throws an exception:
Uncaught Error: No module: InventoryModule
I think it has something to do with it. Manually bootstrapping by calling angular.bootstrap seems to workaround the actual problem.
A similar question was asked here but it did not help me.
I am learning angularjs and I noticed the controller is executed twice.
I have a very simple fiddle example that shows the behavior here
I built the example as I was learning about services and at first I thought it was the injecting of the services into the controller but I commented all the code related to the services and still the controller is executed twice.
My example works but I am afraid I am doing something wrong.
<div ng-app="MyApp">
<div ng-controller="MyCtrl">
{{data1}}
</div>
</div>
var app = angular.module('MyApp', [])
app.service('Service1', function(){
return {
ajxResponse1: 'dataFromService1'
};
});
function MyCtrl($scope, Service1){
alert('Entering MyCtrl');
$scope.data1 = Service1.ajxResponse1;
alert('Exiting MyCtrl');
}
One possible source is this: if you are using Routing and specify the controller in routes - you must not specify it in template that the route uses. We had that problem when this was overlooked.
Your controller was running twice in the fiddle because angular is referenced twice (once via the Frameworks & Extensions drop down and another as an External Resource).
See this updated fiddle where I removed the External Resource and the alerts only show up once.
The code remains unchanged:
function MyCtrl($scope, Service1, Service2, Service3){
alert('Entering MyCtrl');
$scope.data1 = Service1.ajxResponse1;
$scope.data2 = Service2.ajxResponse2;
$scope.data3 = Service3.ajxResponse3;
alert('Exiting MyCtrl');
}
I had a similar problem and it was due to slashes in my routing.
I had something like /post{slug:[a-z0-9-]*/} for my route and when visiting the page at domain.com/post it would redirect to the version with a slash on the end.
Took me ages to work it out!
Edit:
Actually, just took a more detailed look at your code and noticed there is no routing in there, so this is probably not the cause in your case.
Might be useful for people like me who were looking for a different solution though.
For all the people using rails and angularjs:
The rails framework that maps URLS to views and loads them clashes with the angularjs $route even when you have a single-view application.
To prevent the double-loading of your controller:
go to application.js and remove "//= require turbolinks
You're welcome.