Do AngularJS Controllers ever use more than one action/setup method? - angularjs

Most of the examples of AngularJS controllers that I have seen, usually have a single action method that wires everything up for the view. On the other hand, in controllers that use the MVC pattern, rather than AngularJS's MVW, there are usually multiple action methods per controller, but this does not appear to be the case with AngularJS.
Granted one can wire into the $scope (or some other object) any number of methods that execute behavior, still this does seem to be the same as MVC's action methods, since they do not automatically accept direct route input.
I'm interested because I'm trying to convert an existing Asp.net MVC app to angular and I'm trying to decide the best organizational breakdown for the controllers.
Are my various assumptions correct?
Do AngularJS Controllers ever use more than one action/setup method?
Are angular controllers ever broken down into individual actions?
Or does an angular controller have more or less one action, though the routing and view might be different?
Update:
Requested Example - AngularJS controller:
myApp.controller('DoubleController', ['$scope', function($scope) {
$scope.double = function(value) { return value * 2; };
}]);
Asp.Net Controller MVC example:
public class CardController : Controller
{
private readonly IService _service;
public CardController(IService service)
{
_service = service;
}
public ActionResult Index(Guid gameId)
{
var model = _service.GenerateCardBuyDisplayModel(gameId);
return View(model);
}
public ActionResult BuyCards(ExecuteBuyModel input)
{
_service.ExecuteBuy(input.GameId, input.CardsToBuy);
return RedirectToAction("Index", "Game", new { id = input.GameId});
}
}
Ruby on Rails controller example:
class ClientsController < ApplicationController
# This action uses query string parameters because it gets run
# by an HTTP GET request, but this does not make any difference
# to the way in which the parameters are accessed. The URL for
# this action would look like this in order to list activated
# clients: /clients?status=activated
def index
if params[:status] == "activated"
#clients = Client.activated
else
#clients = Client.inactivated
end
end
# This action uses POST parameters. They are most likely coming
# from an HTML form which the user has submitted. The URL for
# this RESTful request will be "/clients", and the data will be
# sent as part of the request body.
def create
#client = Client.new(params[:client])
if #client.save
redirect_to #client
else
# This line overrides the default rendering behavior, which
# would have been to render the "create" view.
render "new"
end
end
end
If you look at these three examples, the AngularJS has only a single constructor/setup method, while the Asp.net MVC example has a constructor and two action methods The Ruby of rails example does not even have a visible constructor, simply action methods. The Asp.net MVC example (or the Ruby on Rails example) is similar to how many actions work in other MVC implementations. In AngularJS I guess there is only one action/constructor method, where in one would attach any additional behavior. The Asp.net MVC example on the other hand has both a constructor and two action methods that can both be routed to in different ways. similar to the single AngularJS contrustor/action.

From what I can tell AngularJS controllers do not have traditional action methods, like MVC controllers. Instead whatever a controller can do must be defined in the single constructor method or configured using the routing in the application configuration. If you need a setup that is different from the constructor then its probably a good place to use a new controller.
Later I asked in the angular IRC chatroom:
Angular controllers don't really have action methods like they do in
other MVC implementations like Ruby on Rails or Asp.net MVC? right?
to which wafflejock responded:
nothing is required or given to you basically
and
it's just the barebones structure with no "base" objects to extend
from or interface to implement
robdubya also mentioned:
unless you want to get all future-sexy
https://gist.github.com/robwormald/bc87cb187e8f96c4e5f0

Related

JHipster: After generating an entity, how can I access a custom java function in my EntityResource from the frontend?

I have been using JHipster a little bit and have a specific question.
I have an entity with all my back-end, CRUD operations generated by JHipster. I have customized my CRUD operations and have been able to add to the Resource to fit my needs, no problem with that.
However, in one of the forms that I have for the ADD operations, I need a button that would call the backend, do some work, and send the result back to the front-end. This needs to happen without submitting the form.
<button type="button" ng-click="test()" class="btn btn-info">Test</button>
In my controller:
$scope.test = (function () {
alert("test");
MyEntity.test();
});
Finally, my backend code in my resource java file:
public void testDatabase() {
System.out.println("Test");
}
I know that I will eventually have to return a ResponseEntity type, in order to send some data back to my front-end, but right now, I cannot even get my backend method to be called from the test function that I have defined in my controller.
What would be the best approach in order to achieve this, in the context of JHipster?
You are talking about 2 different problems, both leading to a lack of experience in the underlying frameworks.
the first problem is your not submitting form....this is already discussed by a similar problem here.
the second problem is your backend code, which I don't know where you putted in, wether you annotated it and so on...
generally you should always work with ResponseEntity, because you are building REST and you need the power to work with the HTTP protocol, in particular with response codes. Next....you never System.out.println in spring....if you want to have output, you use Logger, for response types you should return something...like
public String test() {
return "test";
}
or
public ResponseEntity<String> test() {
return ResponseEntity.ok("test");
}
general, you should review some more material to both spring boot and angularjs, then JHipster will help you to find a working way to wire things
Best regards

Angular: Single service in multiple files

I have a singleton that creates classes for me. Each class is in a separate file.
// singleton.js
angular.module('mymodule')
.service('singleton', SingletonClass)
// someclass1.js, someclass2.js, ...
// Multiple files with same layout. Each web page has different # of these files.
// Therefore, it's hard to inject them statically
// (ie, via aggregator service/factory).
angular.module('mymodule')
.??('someClass', function(singleton) {
classOptions = {}; // details here
// creates a class with options and adds it to `singleton`s cache
singleton.addClass(classOptions);
})
// yet another file
angular.module('mymodule')
.controller('myController', function(singleton) {
singleton.getClasses(); // gets all classes added by #addClass method
});
Basically, I want each individual "class" to be self-contained in its own file similar to how modules are self-contained. That means I don't want want singleton or any aggregator service/factory to know of the existence of these classes in its creation.
Edit:
I'd like to clarify: I'm using singleton instead of individually injecting the created classes because I don't yet know which classes will be created yet. The web page will dynamically load certain js files. Each file will inject the singleton object and use the addClass method to create a new class and store it inside the singleton object itself. The controllers using singleton.getClasses() won't know how many or which classes it's getting, but they have a uniform interface which allows it to use them in a predictable fashion.
You could try setting up providers for each class (per my comment above), though that seems . . . time consuming. Maybe you just don't need it? Make each class a separate file in a closure (like you use to need to do with jquery), and grab the singleton object from the injector:
// file 1 - Add other files for other classes.
;(function(window, $) {
$(function() {
var classOptions = {};
$('body').injector().get('singleton').addClass(classOptions);
});
})(window, jQuery);
This is not exactly the angular way, and angular purists will call for your head, but I think it will achieve what you're after if you don't want to mess with providers.

pass data between controllers

I'm stating to learn AngularJS, coming from a lot of different MV* frameworks.
I like the framework, however I'm having trouble with passing data between Controllers.
Suppose I have a screen with some input (input.html) and a controller, let's say InputCtrl.
There's a button on this view which takes you to another screen, let's say approve (approve.html) with a controller ApproveCtrl.
This ApproveCtrl needs data from the InputCtrl. This seems like a very common scenario in bigger applications.
In my previous MV* frameworks, this would be handled like (pseudo-code):
var self = this;
onClick = function() {
var approveCtrl = DI.resolve(ApproveCtrl);
approveCtrl.property1 = self.property1;
approveCtrl.property1 = self.property2;
self.router.show(approveCtrl);
}
It would work like Controller- first.
You create the controller first, having a chance to put it in the right state; afterwards the View gets created.
Now, in AngularJS, I'm handling this like:
var self = this;
onClick = function(){
self.$locationService.path('approve');
}
This works like View-first.
You say to which view / route to navigate, the Controller gets created by the framework.
I find it hard to control the state of the created Controller and pass data to it.
I've seen and tried following approaches, but all have it's own issues in my opinion:
Inject a shared service into InputCtrl & ApproveCtrl and put all data to be shared on this service
This looks like a dirty work-around; the state in the shared service becomes global state, while I just need it to pass data to the ApproveCtrl
The lifetime of this shared service is way longer than what I need it for - just to pass data to the ApproveCtrl
Pass the data in $routeParams
This gets quite messy when having the pass a lot of parameters
Use $scope events
Conceptually, this is not something I would use events for - I just need to pass data to the ApproveCtrl, nothing event-ish
This is quite cumbersome; I have to send an event to the parent first, that would then broadcast it to it's children
Am I missing something here? Am I creating too many small Controllers?
Am I trying to hold on to habits from other frameworks too much here?
In terms of structure AngularJS is more Modular than MVC one.
Classic MVC describes 3 simple layers which interact with each other in such way that Controller stitches Model with View (and Model shouldn't rather work with View directly or vice versa).
In Angular you can have multiple, some completely optional, entities which can interact between each other in multiple ways, for example:
That's why there are multiple ways of communicating your data between different entities. You can:
Send messages directly between controllers using difference between this and $scope
Send messages using events
Send messages using shared system (Note: same link as above, answer shows both techniques)
or
Send messages using AJAX backend
Send messages using external system (such as MQ)
...and a lot more. Due to its diversity Angular allows developer/designer to choose way they are most comfortable with and carry on. I recommend reading AngularJS Developer Guide where you can find blessed solutions to some common problems.
If your intent is to simply share data between two views, a service is probably the way to go. If you are interested in persisting to a data store, you may want to consider some sort of back-end service such as a REST API. Take a look at the $http service for this.
Even if XLII gave a complete response, I found this tutorial using a service. It's very interesting and a simple way for sharing data between controlers using the 2 ways binding property : https://egghead.io/lessons/angularjs-sharing-data-between-controllers
I still havn't used it for now.
Otherwise there is also this other way, based on events : http://www.objectpartners.com/2013/08/21/using-services-and-messages-to-share-data-between-controllers-in-angularjs/
If you wish to pass simple string data from one page (page1) to another page (page2), one solution is to use traditional url parameters. Invoke the page2 route url with parameter like "/page2/param1/param2". The controller of page2 will receive the parameters in "routeParams". You will be able to access parameteres as routeParams.param1 and routeParams.param2. The code below is adopted from: How to get the url parameters using angular js
Invoke the page2 route from page1's controller(js) or a url in its html with parameters as:
"/page2/param1/param2"
Page2 route:
$routeProvider.when('/page2/:param1/:param2', {
templateUrl: 'pages/page2.html',
controller: 'Page2Ctrl'
});
And the controller:
.controller('Page2Ctrl', ['$scope','$routeParams', function($scope, $routeParams) {
$scope.param1 = $routeParams.param1;
$scope.param2 = $routeParams.param2;
...
}]);
Now you can access the parameters (param1 and param2) values in your page2's html/template as well.

AngularJS - Changing the URL used in $resource.query method

I'm using AngularJS to integrate with a REST service which has already been built.
The REST API uses the following form for queries:
http://the.site/person/search/smith%20male (this searches for people called smith who are male)
I'm aware that this form isn't the best and will be ultimately getting the API changed to use a URL parameter.
Currently I'm just defining a resource inside my controller:
$scope.Summary = $resource("http://the.site/person/search");
this.Summary.query({ terms : 'smith male' });
but that generates URL's of the form /person/Search?terms=smith%20male
Is there a way to modify or override the URL used? I'm more familiar with Backbone where I was able to provide a url() function in my which generated the correct form of URL.
$scope.Summary = $resource("http://the.site/person/search/:terms");
this.Summary.query({ terms : 'smith male' });

Putting ajax and non-ajax actions in the same controller in CakePHP

I've run into a problem in my CakePHP app as a result of adding some ajax actions.
My table is called orders so obviously my controller is called OrdersController and the model is called Order
It is my understanding of CakePHP's best practices that if I am going to run any logic on the Order model, that it should be done in the OrdersController. This is fine for the basic CRUD stuff but now that some of my views need to send ajax requests to manipulate Order data I have a problem.
The problem is that for ajax to work properly, I have to put this at the beginning of the OrdersController
var $layout = 'ajax'; // uses an empty layout
var $autoRender=false; // renders nothing by default
Then, to stop the security component interfering with my Ajax form submissions, I also need this:
public function beforeFilter() {
parent::beforeFilter();
$this->Security->csrfUseOnce = false;
$this->Security->csrfExpires = '+1 hour';
}
None of this would be a problem if the controller was only being used for Ajax requests, but the problem is that it's being used for regular Cake actions too.
Is the answer that I should have two controllers? One for regular actions and one for ajax actions? This doesn't seem to be mentioned in the Cake docs and it doesn't seem like a very efficient way of doing things.
I know I can change the layout and possibly the auto-render setting on a per-action basis, but I don't see how it's possible to do this with the csrf settings, which need to be in the beforeFilter.
No need for a separate controller. Use cakes request handler. In your controller method, you can test if it's an Ajax request.
if ($this->request->is('ajax')) {
//set to Ajax layout and security settings, etc
You'll need to include the request handler component at the top of your controller:
public $components = array('RequestHandler');
See this page in the cook book For more info: http://book.cakephp.org/2.0/en/core-libraries/components/request-handling.html

Resources