bootstrap AngularJS service with asynchronous data using angularAMD - javascript

I have a problem pretty much similar than the issue exposed in this question (AngularJS : Initialize service with asynchronous data). My difference is that I'm using angularAMD to load scripts asynchronously and I just can't fit the approaches above in the following app.config:
define(['angularAMD'], function (angularAMD) {
var app = angular.module('app', []);
app.config(['$routeProvider', function ($routeProvider) {
// some code here
}]);
app.run(['srvRules', function (srvRules) {
srvRules.getRules().then(function (result) {
// I need to bootstrap only after I get the rules from the server
});
}]);
return angularAMD.bootstrap(app);
});
EDIT 1
This is the approach I'm trying to accomplish: https://stackoverflow.com/a/21189057/2407203
EDIT 2
Adding more information: I have a webapi as the backend, it is a legacy system which provides all kinds of business rules needed to set up the application. The main information provided at this moment are:
I use $translateProvider(http://angular-translate.github.io) to dinamically load the dictionary with the current culture. All the texts should be taken from this dictionary.
I have a service that monitors all route changes and allows or restricts the access based on the rules returned.
Some information should be placed on the screen based on the rules. Those information are all encapsuled inside a directive on the initial html.
Some html controls may appear or not based on the rules as well.

There's really no easy or elegant way out. I ended up doing the following:
Started using ui-router(https://github.com/angular-ui/ui-router) instead of ngRoute;
Created a root abstract state, parent of all other states;
Used the resolve section of the root state to load all data needed before any controller get instantiated

Related

AngularJS module architecture

I am planning to create several modules in my company's application and I'm having trouble designing the architecture for the modules. I have done research and it seems like either you are supposed to use one module per page, or create a 'master' module that depends on all of your other modules. I don't like this approach because it means I have to load all of the javascript for every aspect of my application for every single page. That seems inherently wrong, but I also can't seem to figure out how to handle it the other way if I need to use one module in multiple places on a page. For example, I have a membership module that I have and I'm attaching to the header section of my web page. This would be intended for logging in, registration, and performing a 'forgot password' type workflow.
On another page dedicated to changing a password (from a reset link) the header is also present, but I want to include the password reset functionality in the membership module. I've read that one methodology of designing your application is by functionality/feature. I figured membership was an appropriate application of that, but now I'm not sure since I am having trouble applying the membership module more than once on any particular page.
Am I on the right track, or is there a preferred method for this? Should I have a separate module for the header and one for the rest of the page? Should I just bite the bullet and load everything? (I hope not...)
I should also note that this is an ASP.Net MVC application where we are still heavily relying on MVC for serving views and partial views. As such I wanted to use a render javascript section to dynamically load only the javascript necessary for that page to function. Is this a farce?
<header ng-app="membership">
//stuff for header membership functions
</header>
<div ng-app="membership">
//somewhere else that needs membership, outside of header
</div>
I personally like Mini SPAs (Silos) instead of full SPA. You can watch Miguel A Castro's video, and download the source at his website.
What it does is when a request comes in, it goes to ASP.Net MVC Route first. Then, Angular Route takes over the rest. It is a very slick design.
FYI: Angular 2 is right around the corner, so I went ahead and updated those to Angular 1.5 Compotent so that I can convert to Angular 2 easily later.
If you want, you can stop there. I went one step future, and use Strongly Typed Views using Matt Honeycutt's Building Strongly-typed AngularJS Apps with ASP.NET MVC 5 approach.
Then I implemented Angular Helpers like Axel Zarate's ANGULAR.NET – HELPERS FOR ASP .NET MVC 4.
On an Angular application, as it is a Single Page Application, yes, all your javascript must be loaded. It's the code of your application and it's necessary. That's done only once on first page load.
You're always on the same page, but on a different state.
One good approach is to define a master module who include all other modules. Those modules can also include other "sub modules" they need.
angular.module('App', [
'App.Membership'
// ...
// All others modules you need, including 3rd party modules
])
Then, on each module, you can define the different states associated and their controller
angular.module('App.Membership', [
// Module dependencies
])
.config(['$stateProvider', function($stateProvider) {
//State definition
$stateProvider.state('membership', {
parent: 'app',
url: '/member',
controller: 'MembershipCtrl',
template: '<ui-view/>'
});
}]);
You can also add a global controller to handle elements who are always present, like a header.
Hope this helps

Implement a logical part as Generic one in AngularsJs

I have recently started working on ANGULARJS in which I was encountered a case where I need some guidance to go through. Am implementing a message section in my application(ASP NET MVC - ANGULARJS).Currently I have implemented the message section for a specific module under a particular ng-app and under particular ng-controller. Now I need the same functionality to be used inside another module. It's like duplicating the same code again that ng-app under that ng-controller which was not a good approach. I just wanted like and plug and play kind of approach for my ANGULARJS code.
I have used 2 service,1 directive under that particular ng-app and some functions inside a particular controller. All I want is to make these one a common code and to be used inside under any ng-app and ng-controller.
Is this possible? If so how can I achieve.
Let me know if the query was unclear
You said you used 2 service, 1 directive, and controller etc for your messaging feature. If you want to re-use it across various applications, you need to bundle all of this as a module. for example:
angular.module('customMessaging', [])
.controller('messagingCtrl', function(messenger, messageManager) {
....
})
.directive('messagingDir', function() {
return {
controller: 'messagingCtrl'
...
}
})
.service('messenger', function() {
...
})
.service('messageManager', function() {
...
})
Now you can specify this as a dependency of any of your angular applications as shown below to access the directive, services and controller anywhere in the app:
angular.module('myfirstApp', ['customMessaging']);
angular.module('mySecondApp', ['customMessaging']);
Thanks for the suggestions. I have moved the message related functions such as services, directive and controller related functions into separate JavaScript file . And invoked this JavaScript file where I need message related functionalities.
Let us say that JS as Message.JS . In Message.JS I have used the app variable(Instantiated app from the JS Specific to the page globally).
JS specific to that page
var app = angular.module('appname',[]);
app.controller(...)
Message.JS
I have used the same app in my message.JS since message controller falls under that app.
app.service(...)
app.controller('messagecontroller',[]...)
When ever I need to invoke a function inside MessageController I will use Broadcast in angular to achieve this.For more info http://www.dotnet-tricks.com/Tutorial/angularjs/HM0L291214-Understanding-$emit,-$broadcast-and-$on-in-AngularJS.html
Regards,
Selvam.M

Can I link an external javascript file to an AngularJS controller?

This may be a dumb question. I know AngularJS controllers use javascript code to keep the application logic outside of the view. But I was wondering if I could link an external javascript file to a controller so it didn't have to be so long.
If it is possible would you also share the syntax of how I would do this. Something like:
app.controller('demoCtrl', ['$scope', function ($scope) {
$scope.msgtxt='Hello World';
src=somejavascriptfile.js;
}]);
If your issue is that the controller logic is too long, you are correct that it is a code smell. You want to make the controller as thin as possible, just enough logic to handle the view events and updating the model (scope). If you want to refactor your controller code, the first step is to extract out the logic into service(s) (in angular lingo providers / factories / services). The services can then be injected into your controller, similar to how you have injected the $scope service.
Read this sitepoint article for details on how to do this.
The next step might be look for logic (mainly UI related) which can extracted into directives.
In case you need to use an external javascript library within your angular application, the optimal way is to add that script to the scripts section of your html file, and wrap the functionality in a service or a directive (if it is UI related). Make sure to check if there are angular modules available out there for the 3rd party library you want to pull in.
Not only you can split your controller code among different files, but you probably should do that. An angular controller is responsible for the business logic behind a view, and only for that. You are doing it wrong if, inside the controller, you are (list not exhaustive) :
accessing your backend from it
manipulating the DOM
writing utility code for showing alerts in your application (for example)
Your components should be concise and of a single responsibility.
Here follows an example of how you would export some part of your code in a service. You do not link a js file from a controller, but you load it in your page, and inject the service as an argument of your controller :
1) Load your service in index.html :
<script src="js/factories/loggerService.js"></script>
2) Implement your service in loggerService.js
app.factories('loggerService', function () {
//
// Implement here some logging methods
//
// IMPORTANT: do not bloat this service with methods not related
// with logging
//
});
3) Inject your service in your controller :
app.controller('demoCtrl', function ($scope, loggerService) {
loggerService.info(...)
});
By the way, this loggerService would be useful only if you need something different than the service provided by angular built-in service $log
In a different file, define a service containing the logic and just call it from the controller.
app.controller('demoCtrl', ['$scope', function (ServiceFromDifferentFile, $scope) {
$scope.msgtxt='Hello World';
ServiceFromDifferentFile.doStuff()
}]);

Correct paradigm for mixing angular code with external code

Angular Newbie here. I'm trying to understand the paradigm to use when developing an Angular app so I can use external libraries while keeping the Angular app reusable.
So imagine I've got a form that uses ng-submit:
<form ng-submit="submit()">...<!--code goes here --></form>
And then inside the corresponding ng-app and ng-controller (assume those are declared in a parent element), I've got my submit function. But say, on this page only, I want to use a custom alert library after submitting:
$scope.submit = function(){
// code goes here to submit form data
//now tell the user that save was successful
customAlertLibrary.alert("your data has been saved")
}
Now that's not reusable code, is it? I may want to reuse this ng-app on another page to modify and submit data, but don't want to use the custom alert library. It seems like you're trapped because the ng-submit attribute restricts you to functions inside the corresponding ng-app, not external functions. So what is the correct way to invoke other Javascript code alongside my Angular code without baking it into the model?
This question is very similar to this question about making lodash available in templates. There are many ways of adding external (or in-app) code or data-structures to your Angular scope. I prefer to add special-purpose stuff to each scope individually, and general-purpose utilities (such as lodash or momentjs) globally:
app
.run(['$rootScope', function($rootScope) {
$rootScope._ = _;
$rootScope.moment= moment;
// or:
// $rootScope.util = {
// _: _,
// moment: moment
// };
});
If customAlertLibrary isn't crucial to your app, I'd say do something like this
$scope.submit = function(){
// code goes here to submit form data
//now tell the user that save was successful
if ($window.customAlertLibrary) {
customAlertLibrary.alert("your data has been saved");
}
}
Otherwise, I'd suggest using Bower to manage dependencies. You install packages with Bower, and your own app can be a package that gets included and installed by other apps. Any dependency your app has gets installed as well (the user still has to include it on their own end in a <script> tag)

How can I get an environment specific URL into my AngularJS controller?

Situation
Our web project in production has a root URL like so: http://example.com. Our local dev instances (don't ask me why) default to a URL like so: http://localhost/SubDir where SubDir is a placeholder for the actual virtual subdirectory in IIS.
This is not the problem. As much as I would like to abolish that subdirectory URL thing, that is only illustrating a problem. If we were to move to a different domain or URL later on that incorporates a subdirectory URL, it would not be a problem for all of the instances in code where we use helpers to generate URLs (e.g. #Url.Action("GetUpdates"), etc).
Currently we have quite a bit of javascript that has been moved to external .js files that uses jQuery to get URL strings from hidden inputs whose values have been set to a Url helper like above. This is not too bad, it works.
The Problem
AngularJs. It is not the problem. It has however uncovered the problem. We want to remove jQuery from the project eventually. Right now, I am getting the URLs in my controller using jQuery (I am willing to break rules in an effort to get something out on time if I can be reasonably assured I will be given time to fix it later). It is now time to fix it, and I am at a loss.
Between the two environments, I get the following from #Url.Action("GetUpdates"):
On http://example.com/: => /Contest/GetUpdates
On http://localhost/SubDir: => /SubDir/Contest/GetUpdates
The Question
How can I get an environment dependent URL into my AngularJs controller without the use of the helpers in that controllers file? I originally thought it might be as simple as using the hidden inputs and setting the ng-model, but does not seem to have worked. I have also looked into using an extension, RazorJS, but hoped that there would be a better way of doing it more inline with the Angular paradigm.
Anyone have any ideas? How do you get URLs into your controllers?
If you are able to change your environment config server side you can put the variable inline in a module constant. Then you can inject into your main app.
Here's a Plunker
// inline
angular.module('Preload',[]).contstant('CONFIG', {'BASE_URL':'http://localhost/foo'});
// inject
var app = angular.module('MainApp', ['Preload']);
// Controller
app.controller('MainCtrl', function($scope, CONFIG) {
$scope.base_url = CONFIG.BASE_URL;

Categories

Resources