Error when registering an AngularJS controller dynamically in a separate file - ruby-on-rails

So I'm an Angular noob trying to introduce AngularJS to an already existent RoR environment.
Since it's a relatively heavy and robust web app, I thought the best way to go about it would be to write a controller for each section in its' own file (coffee, for the record), and load it with the view through $routeProvider, registering the controller dynamically by doing something like this (omitting irrelevant parts):
app.config [
"$routeProvider", "$controllerProvider",
($routeProvider, $controllerProvider) ->
app.registerCtrl = $controllerProvider.register
$routeProvider
.when("url1",
templateUrl: "url1.html.haml"
controller: "url1Ctrl"
)
.when("url2"
templateUrl: "url2.html.haml"
controller: "url2Ctrl"
)
.otherwise redirectTo: "/homepage"
I load the main js file (and in it the above snippet) in the layout file, and each designated controller file in the appropriate view (that is dynamic, obviously). In each of them, I try to load the relevant controller using:
#url1Ctrl = app.registerCtrl 'url1Ctrl', [
'$scope', .....,
( $scope, ....) ->
# some logic
Problem is, I get an error saying "Uncaught TypeError: undefined is not a function". I thought I was doing something wrong with the provider function but it seems I'm being a lawful citizen there.
Also read a bunch of similar questions on SO:
How to separate Controller file in angularjs (basically using ".controller" instead of registering it? Didn't work for me)
Separating Controllers in AngularJS (same idea)
How to create separate AngularJS controller files? (same, but the controller files are always loaded, not lazy-loaded dynamically...)
Loading an AngularJS controller dynamically (seems like an over-complication?)
AngularJS Controller Not Registering (tried it, not the same issue i'm having, it seems)
Would love some input on what part of Angular I'm misinterpreting here.

Related

Multipage SPAs with AngularJS & Rails using ui-router

I have a Rails application in which I am trying to replace some views with AngularJS, but not all. In each view I replace, I want it to basically act as if it is it's own SPA. I am also trying to use ui-router to manage states within each of these SPAs.
For example, I have a Rails route that maps to a view ".../checkout/1. This triggers a Rails view in which I load the initial SPA for the flow and then let angular take over. I would like to setup ui-router states that are just specific to this checkout flow.
Where I am getting stuck is how to have states that are only specific for that flow with that base url. If I setup the states:
$stateProvider
.state('start', {
url: "/",
templateUrl: "..."
})
.state('route2', {
url: "/route2",
templateUrl: "..."
})
.state('route3', {
url: "/route3",
templateUrl: "..."
});
This works and for .../checkout/1#/, .../checkout/1#/route2, .../checkout/1#/route3.
However, it also work in my other SPA views which I do not want. So, if I do another rails view that uses another SPA, e.g. .../item/1 then the above route will also work for .../item/1#/ and .../item/1#/route2, etc.
Instead, I would like each to be it's own SPA and not conflict with each other. I am not sure how to do this. Can ui-router be somehow namespaced using the base url or can I have independent SPAs that have different stateProviders? Any thoughts on how I should go about this?
Thanks
Each SPA should have its own angular module defining an application with its own state definitions. So there can't be any conflict.

ng-route with phonegap loading correct view even if the templateUrl doesnt exist

I am using ng-route to load the partial templates inside my phonegap app. I did a $location.path('/assessments') to load a specific partial 'assessments.html'.
`//..snippet
$routeProvider
.when('/assessments', {
templateUrl: 'partials/assessment.html',
controller: 'AssessCtrl'
})`
I know from the logs that the controller AssessCtrl is being called. It's also showing the correct assessment.html on the iPad.
However, if in the filesystem I change the name of the assessment.html file to xyz.html, it still loads the correct template.
How can I make sure the template is being loaded from the iPad and not being returned from the server (which I hit to get the data).

Backbone With Rails

I'm getting my data from a service and then setting the data to my bean object and want to using the same data in my view displaying it in a form in rails view now. Now I want to validate this form using backbone.
I'm new to both Rails and Backbone.
Kindly give me an idea on how to proceed on this.
I think perhaps you are confused about how web applications work. Backbone is a client-side framework; it uses Javascript code that is run in your users' browsers. Rails is a server-side framework; it uses Ruby code that runs on your server.
Given all that, your Backbone code and your Rails code by definition have to be completely separate. The two can communicate in only two ways:
1) Your Rails code can write <script> tags to the page (inside a .html.erb file) and put variable data there; for instance:
<script>
var myVarFromRails = '<%= someRailsVariable %>';
</script>
When that comes back from the server (ie. when you view source the page) that will get converted to:
<script>
var myVarFromRails = 'foo';
</script>
(assuming 'foo' was the value of someRailsVariable).
2) Your Javacript code can make AJAX requests to Rails URLs, and whatever the Rails code spits out there will come back as the response to your AJAX request. In other words you can do:
$.ajax({url: someRailsUrl, complete: function(response) {
// whatever the server sent back will be inside the "response" variable
}});
Other than that the two are pretty much entirely separate, and if you want to do the same thing in both of them (eg. validate a form) you essentially have to write the code twice, once for Ruby and once for Javascript.
I say "essentially" because there are Rails plug-ins which do #1 and #2 for you in different ways. I'm not a Rails expert, and even if I was there are so many of these plug-ins that you really need to look for yourself to find out what exists and what makes sense for your codebase.
Hope that helps.
* EDIT *
I know I just said I wouldn't list libraries, but then I realized it'd be more helpful if I at least provided a few to get you started. Just don't take these as canon; they're simply some popular libraries at the moment, but they may or may not be right for you.
https://github.com/codebrew/backbone-rails
https://github.com/meleyal/backbone-on-rails
https://github.com/aflatter/backbone-rails
https://learn.thoughtbot.com/products/1-backbone-js-on-rails
http://kiranb.scripts.mit.edu/backbone-slides/
That last two aren't actually libraries, they're a book/presentation, but I thought they might be useful.

Backbone.js with Rails

I'm currently trying Backbone.js along with a rails app. My problem is, that I don't know how to implement the Backbone controllers and views with my rails app. I've read a lot of tutorials, but they are always using just one controller in backbone.js.
For example, I have two controllers in rails.
Activities Controller
Includes two views, a google map and a search field. The google map is inserted with a backbone view, the searchfield is in HTML and gets its functionality through a backbone view.
The search field should fetch data from my rails model and display markers inside the map.
And the other one is
Users Controller
Here the users profile is viewed, and I want to add some ajax functionality like updating values and other things
In my application.js I start the app using
var App = {
Views: {},
Controllers: {},
Collections: {},
init: function() {
new App.Controllers.Activities();
new App.Controllers.Users();
Backbone.history.start();
}
};
$(function() {
App.init();
});
The problem is, that I don't need the Activities controller in my User Profile and the Users controller in the Rails Activities controller. How could I solve this? Should I try reading the current URL within javascript and then decide which controller is used?
Or should I put the JavaScript file into the application.html.erb and then decide here which controller should be used?
Or is this the wrong way to use backbone.js controllers?
Am I getting sth wrong with the structure of backbone.js? Or am I using the Controllers in a wrong way?
Another question is, how to add little JavaScript, in particular jQuery, functionality through Backbone.js? For example, I want to remove the label inside a field, when the user clicks into the field. Or I want to do some tab-functionality and just toggle the visibility of some elements.
Should I create for each element that is using javascript a Backbone view? Or is this overload?
Hope I made myself clear and anybody can help,
thx!
Why not make use of the routes feature Backbone provides to decide which method to call? The activities controller would contain only routes use for activities, the user controller only for the user handling, and so forth.
Like this you can instantiate the controller just as you do and the routing will decide what happens based on the current location's hash.
If you can't use links with hashes (or there are no such links on your page), I'd simply name my view containers specific enough to attach events only for the current view when needed.
jQuery plugins etc. belong into views IMO. Same goes for your tabs and input hint toggle.
Update
On a general level (and I would not necessarily recommend doing it this way): If you have two methods:
// should be only called for the 'Foo' controller
function foo() {
alert("FOO");
};
// should be only called for the 'Bar' controller
function bar() {
alert("BAR");
};
and want to call only one of them depending on the current Rails controller, create a small helper:
e.g. in you *helpers/application_helper.rb*
def body_class
controller.controller_name
end
then call this method in your layout file (or header partial):
<body class="<%= body_class %>">
…
and use e.g. jQuery to "split" your JS execution:
if ($('body').hasClass('foo')) {
foo();
} else if ($('body').hasClass('bar')) {
bar();
}
I personally use jammit (from the same author of backbone). You can group stylesheets and javascripts files by module and use them on your different pages. So you create a module for your activities view and another for your user view each requiring the necessary JavaScript file. Two nice things about this:
you have only code used on the page loaded on the page
jammit comprsses everything for you
This is the way to go when not creating a single page web app where you relies on # routes to navigate from one controller to another. In your case you have multiple single page apps inside a main rails app.
Im a Backbone.js newb, so please someone correct me if Im wrong, but I think youre confusing what Backbone controllers are used for.
Backbone.js controllers basically consists of hashbang routes(similar to Rails routes) and actions that these routes call. For instance if you have a rails route that will render a view at http://mysite.com/backbone_test and you have a following backbone route:
var MyController = Backbone.Controller.extend({
routes: {
"foo/:bar": "myFirstFunction"
},
myFirstFunction: function(bar){
console.log(bar);
});
then if you go to http://mysite.com/backbone_test#foo/THIS-IS-AMAZING then MyController.MyFirstFunction gets executed and "THIS-IS-AMAZING" gets logged in JS console.
Unless you have a direct need for this sort of hashbang-related functionality, such as saving a state of your JavaScript application via an url (for example: http://my.app.com/#key=value&key=value&ad-infinitum=true ) Id advise against using Backbone controllers. You can get all of the functionality u described via Models Collections and Views.
Nice thing about Controllers and Backbone in general is that its modular and different parts can be used independently.
I guess the summary of this answer is that if you dont have a single page javascript application, do not use Backbone Controllers, rely on your rails controllers instead.

Still having a hard time with RoR MVC approach

I suppose it should do justice to state what I think I know so far as well as what I've done:
1) I created the app and did my first db migration; I now have my dev, test and production databases. The dev db has a table called 'wines'.
2) I made a scaffold which created the necessary files.
3) The basic index/update/destroy methods are set up and I can browse the pages.
4) From what I gather, the ActiveRecord class "Wine" automatically inherits properties from the database? Each column is a property and each row in the table 'wines' is a potentially instantiated object which is called from the wine_controller script.
The problem I'm having now is that I want to create a common layout that all controllers use. The only things that will change will be the page title, potentially some <link> tags in the header, the <body> attributes (javascript onload events most likely) and whatever lies inside the <body> tag.
I find myself looking up functions that will do what I want (like "favicon_link_tag", "stylesheet_link_tag" and "auto_discovery_link_tag"...) but I can't find the right place to PUT them! I know this has something to do with my lack of understanding of how things are executed/inherited. For example if I were to declare #pageTitle in application_controller.rb and use #pageTitle in ApplicationHelper it won't work. Or even using "stylesheet_link_tag" in application_controller.rb throws an error. I'm just not getting something.
How does each thing relate to another in terms of chronological execution, scope, etc.?
In your "app/views" directory there is a folder called "layouts." By default there should be an "application.html.erb" file in there, but if there isn't you can create it.
Your "application" layout file is the default layout file used by any view. However, if you want a particular controller to use a different view, you can override this. See this railscast, and this one is helpful too.
The main thing to understand is the content from any particular view will show up wherever the yield method appears in your application layout. The main 'yield' block gets the view file specified by your controller action, but you can mark anything inside any view to be passed to another yield block instead. For instance, the "title" example you gave could be passed to the head of your application layout. See this railscast for a detailed example of that.
For more, you should read the Rails Guide, and you might want to consider picking up a Rails starter book.
I got my feet wet with "Beginning Rails 3," which was a phenomenal introduction to the framework. A couple days with that book and it was all making sense to me, and I was developing faster than I ever had before. Rails rocks once you get to know it, but it's definitely worth going through a book.
Please continue to ask questions, I'll help if I can :)
-EDIT- To answer your question about control flow, it basically works like this:
Your browser sends a GET request for a particular URL.
The router takes that request, matches it to a controller action, triggers that controller action, and provides the controller any parameters associated with the request. For instance: if you requested example.com/posts/123?color=red this would trigger the SHOW action of your posts_controller, and would pass {:color => 'red'} to the params hash. You would access that using params[:color]
The controller action does its thing, and when it's done it renders output. By default it renders whatever view is located in app/<controller_name>/<action_name>, and will whichever file matches the extension appropriate to the request (ie an AJAX request would trigger <action_name>.js.erb and a GET request would trigger <action_name>.html.erb.
You can override this using the render method, for example by passing render 'foo/bar' to render using the view for FooController, Bar action instead of your current action.
Note that no matter what you render, the data available to the view is whatever is in the specific controller action the router triggered, not the controller action that would 'normally' render that view.
The view file is parsed using the data from the controller that called it. If you have any content_for methods then the view code that is inside the content_for block will go where you tell it, otherwise everything else will go to the main YIELD block in your application layout (or whatever layout your controller specified instead).
The application layout is parsed, and the content from the view is inserted into the appropriate areas.
The page is served to the user.
That's a simplification in some ways, but I think it answers your question. Again, feel free to keep asking :)

Resources