Angular and Rails - javascript

I was following a tutorial on implementation of angular and rails and I ran into problems performing data binding. I followed the tutorial perfectly but I hit a stumbling block I cannot solve. I am trying to display the value of foo in public/templates/home.html.
Here is my code:
public/templates/home.html
Value of "foo": {{ foo }}
app/assets/angular/controllers/HomeCtrl.js.coffee
#restauranteur.controller 'HomeCtrl', ['$scope', ($scope) ->
$scope.foo = 'bar'
]
app/assets/javascripts/main.js.coffee
#restauranteur = angular.module('restauranteur', [])
#restauranteur.config(['$routeProvider', ($routeProvider) ->
$routeProvider.
otherwise({
templateUrl: '../templates/home.html',
controller: 'HomeCtrl'
})
])
app/assets/javascripts/angular/controllers/HomeCtrl.js.coffee
#restauranteur.controller 'HomeCtrl', ['$scope', ($scope) ->
]

The tutorial I was following incorrectly told me to create 2 controllers with the same name. Once I deleted the controller app/assets/angular/controllers/HomeCtrl.js.coffee I was good to go.

Check and see if main.js.cofee file is included, in your chrome console under sources tab. I also had the same issue. This issue comes when you do //=require ./angular or something like that. If you want the file to get included, then just paste it under app/assets/angular directory and after that you might have to shift your angular directory inside app/assets/javascript directory.

Related

AngularJS 1.5 Controllers in Separate Files

I have a hard time understanding this. I'm attempting to put controllers in separate files so that they only deal with 1 thing, ideally, a partial view
My folder structure is like this...
My app.js file is like this.
angular.module('mikevarela', ['ui.router', 'mikevarela.controller.home', 'mikevarela.controller.about', 'mikevarela.controller.audio'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: '../partials/home.partial.html',
controller: 'HomeController'
})
.state('about', {
url: '/about',
templateUrl: '../partials/about.partial.html',
controller: 'AboutController'
})
.state('audio', {
url: '/audio',
templateUrl: '../partials/audio.partial.html',
controller: 'AudioController'
});
});
and my controllers each have a module like this...
angular.module('mikevarela.controller.home', [])
.controller('HomeController', ['$scope', function($scope) {
$scope.title = 'Mike Varela Home Page';
}]);
My issues comes with the intial app declaration. I don't want to have to inject all the controllers in the main array app definition, that would be cumbersome and long winded. Isn't there a way to define the controller at the controller file. Kind of like this
angular.module('mikevarela', []).controller('HomeController', ['$scope', function($scope) {
// stuff here
}]);
Use angular.module('mikevarela').controller..... in subsequent files.
angular.module('mikevarela',[]).controller.....
is equivalent to redefining your app. The second param is requires array.
Quoting official angular.module docs
requires
(optional)
!Array.=
If specified then new module is being created. If unspecified then the module is being retrieved for further configuration.
About your Controllers...
I think you're loading the controllers incorrectly.
You don't need to declare controllers as a dependency. Rather stating module.controller('yourController)` makes that controller available throughout the module.
If your controllers are in separate files, all you need to do to make it available is load it in with a script tag. e.g.
<script src="app.js"></script>
<script src="controller1.js"></script>
<script src="controller2.js"></script>
About your Application Structure...
This is not related to your question, but just coming from someone who's developed using Angular, I'd recommend not grouping your application by controllers/ by rather by feature. See: https://scotch.io/tutorials/angularjs-best-practices-directory-structure

Angular ui-view (UI-Router) not rendering template - plunker included

Question Background:
I am using AngulaJS's UI Router for the first time to create two views within my app.
The Issue:
Plunker link: https://plnkr.co/edit/2XAKa6mDCUyzyOPz2CNK
I feel I'm missing something simple here but I cannot get any route to render the specified html templates set in the app.js.
Eventually I want the Update.html template to render when the submit fucntion of the home.html (search()) is clicked but first off I need to be able to actually render a single view which I currently cannot.
I would expect on-load for the route to render up the home.html page but it wont:
Any help sorting this will be much appreciated.
app.js:
angular
.module('app', [
'ui.router'
])
.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html',
controller: 'HomeController'
})
.state('update', {
url: '/update',
templateUrl: 'Update.html',
controller: 'UpdateController'
})
}])
Looking at your plunker briefly, it looks like your controller files are creating new angular apps with the same name. They were overriding each other so the .config() block didn't exist in the final app. I have updated the controller files in this plunker and it seems to be rendering the first ui view fine:
https://plnkr.co/edit/cdpWWOaBJWL3dONtIXzv?p=preview
Notice in the controller files, the angular.module('app') no longer has the second argument ['ui-bootstrap'] which was causing a new angular app to be created for each controller file. Check it out here in the angular docs.
Beware that using angular.module('myModule', []) will create the module myModule and overwrite any existing module named myModule. Use angular.module('myModule') to retrieve an existing module.
Hope this helps!

WebStorm 11 doesn't recognise my AngularJS controllers

My app is running without any errors, but WebStorm seems to have problems with the way I use my controllers. I declare and link them in my app.js like so:
$routeProvider
.when(...) // Omitted in sample
.when('/register/', {
templateUrl: '/app/components/register/register.html',
controller: 'RegisterController',
controllerAs: 'registerCtrl'
})
.otherwise({
redirectTo: '/home/'
});
And then call them from my templates like so:
<div class="form-group" ng-class="{'has-success': registerCtrl.firstNameValidates()}">
But hovering over registerCtrl shows the message: "Unresolved variable or type registerCtrl".
If I declare my controller using the ngController directive, all is well, but declaring them in app.js is standard AngularJS behaviour too, as far as I can tell... Could it be that WebStorm just doesn't go that far in resolving variables? Has any one gotten it to work?

Injecting Angular modules: Unknown provider

I followed a tutorial on how to organize and Angular project. I have a ng directory that contains all my controllers, services and my routes.js. This is then bundled all together into an app.js by my gulp config.
My module.js is like this:
var app = angular.module('app', [
'ngRoute',
'ui.bootstrap'
]);
Here's a bit of my routes.js:
angular.module('app')
.config(function ($routeProvider) {
.when('/login', { controller: 'LoginCtrl', templateUrl: 'login.html'})
});
Here's what my working LoginCtrl looks like:
angular.module('app')
.controller('LoginCtrl', function($scope, UserSvc) {
$scope.login = function(username, password) {
...
}
})
The tutorial didn't make use of any Angular modules and I wanted to try one out. I added ui.bootstrap to my page from a CDN and try to change the LoginCtrl to:
angular.module('app')
.controller('LoginCtrl', function($scope, $uibModal, UserSvc) {
...
})
But this throws me the following error:
"Error: [$injector:unpr] Unknown provider: $templateRequestProvider <- $templateRequest <- $uibModal
What is causing this error? In every tutorial I find this seems to be how they load a module, the only difference I see is that the tutorial don't seem to be using a router.
PS: Note that if I use an empty module list [] I get the exact same error. If I use a non-existing module ['helloworld'] I get an errorModule 'helloworld' is not available'. So I'm concluding that my `ui.bootstrap' module is indeed available.
EDIT: Plunker fiddle here: http://plnkr.co/edit/FWHQ5ZDAByOWsL9YeMUH?p=preview
angular route is another module you should not only include but also use like this
in the app module creation
means DI of route
angular.module('app', ['ngRoute']);
Please go through the angular route doc
Remove ['ui.bootstrap'] form controller. You should add dependencies only one time but you add it twice so the second dependency list override the first one.
angular.module('app')
.controller('LoginCtrl', function($scope, UserSvc) {
... })
your routes snippet looks wrong, you should be hanging the when call off $routeProvider and maybe declare $routeProvider as an injected val if it's not being picked up e.g.
angular.module('app')
.config(["$routeProvider", function ($routeProvider) {
$routeProvider.when('/login', { controller: 'LoginCtrl', templateUrl: 'login.html'})
}]);
I have checked your link. I think there is a serious issue with angular and ui bootstrap version.In ui-boostrap dashboard, it is written that 0.12.0 is the last version that supports AngularJS 1.2.x. I have tried with all combinations but it doesn't work with your angular version.
I suggest you to change angular version to latest and ui-bootstrap version to latest so it will work.
Please check out this working Plukr
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular-route.js'></script> //change this to latest also.
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.0.3/ui-bootstrap.min.js'></script>
<script src='./app.js'></script>
If you want to go with your angular version only. I'd request you to do some R&D. Try with different versions of ui-bootstrap. still if it doesn't work you can make PR.

AngularJS + Rails - Problems when compressing assets

I recently created an AngularJS 1.0.0rc8 app with a Rails 3.2.3 back-end and it worked fine in development, but after deploying to Heroku there was a Unknown Provider error - apparently the app could not see the service object.
I know that it's now necessary to include angular-resource.js as a separate file and inject ngResource into the app module like this:
// main app javascript file
'use strict';
angular.module('contactapp', ['ngResource']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/contacts', {template: 'assets/app/partials/contact-list.html', controller: ContactListCtrl}).
when('/contacts/new', {template: 'assets/app/partials/new-contact.html', controller: ContactListCtrl}).
when('/contacts/:contact_id', {template: 'assets/app/partials/contact-detail.html', controller: ContactDetailCtrl}).
otherwise({redirectTo: '/contacts'});
}]);
I also know that when files are minified that the controllers can't tell what their dependencies are unless they are also injected into the controller objects like this:
ContactListCtrl.$inject = ['$scope', '$http', 'Contacts'];
I've also tried doing it the other way that Angular recommends with bracket notation and passing in a function like this:
var ContactListCtrl= ['$scope', '$http', 'Contacts', function($scope, $http, Contacts) { /* constructor body */ }];
However, none of this seems to work.
The only way my application could see the resource provided was by turning off asset compression in the Production.rb file, like this:
# Compress JavaScripts and CSS
config.assets.compress = false
It took several hours for me to figure this out, but I recently saw another Rails + AngularJS app that had the same issue.
Jens Krause came to the same conclusion and explains it on his blog: http://www.websector.de/blog/2012/01/17/fun-with-angularjs-rails-coffeescript-sass-another-cafe-townsend-example/
If I have a relatively large app, and I need to compress the assets, how do I get around this using Angular with Rails?
Thanks.
If you're using Rails 4, change your js_compressor in your production and staging environments to:
config.assets.js_compressor = Uglifier.new(mangle: false)
I think the problem is that your minifier is still obfusticating the variable name of the control itself (ContactListCtrl -> a or whatever it does).
Have you tried defining your controllers with the module.controller function?
angular.module('myModule', [])
.controller('Controller1', ['dep1', 'dep2', function(dep1, dep2) {
//code
}]);
Adding this line to my config/environments/production.rb did the trick for me:
config.assets.js_compressor = Sprockets::LazyCompressor.new { Uglifier.new(:mangle => false) }

Categories