How to configure factory externally in AngularJS - javascript

Say I am building a C# application with AngularJS.
I want to set up configuration object that comes from server side and basically inject that configuration into a factory. Where the factory resides in another .JS file.
How would go about doing that?
I have a JS fiddle example set up here:
http://jsfiddle.net/f89tS/7/

You could use module's constants for configuration objects coming from the server. Using constants is pretty easy, you could generate this on the server-side:
app.constant('CONSTANTS', {zoomLevel: 8});
and then, in your factory you can inject constants:
app.factory('map', function(CONSTANTS){
return {
zoomLevel: CONSTANTS.zoomLevel
};
});
Constants are really good for the server-generated settings since, once generated and sent to the client those can't change.
Finally, here is the working jsFiddle: http://jsfiddle.net/pkozlowski_opensource/JZcys/1/

Here is an example of how I accomplished something similar by wrapping my bootstrap call around my own run method.
It then uses a naming convention to inject configuration options inline from your aspx page, which could be set via c# property.
I don't know if this is the 'angular' way, but it has worked well thus far.
http://jsfiddle.net/xpressivecode/dVM9b/

Related

One inject from multiple constants - Angular

I am using Angular constant as an configuration file for my services, my problem is that this file can become huge and i am would like to separate the configuration into multiple files. But i donĀ“t want to create a new Angular constant that i need to inject in the services that uses constants.
Is there a way to have only one main constant file that requires all the other files so that there is only one inject into the services? Or is it possibly to create one constant from all js files in a specific folder?
Other solutions to this problem would also be very helpful.
You can use $provide.decorator for that:
$provide.decorator('yourSettings', ['$delegate', function ($delegate) {
$delegate.newProp = 'new value';
return delegate;
}]);
See docs.

Best way to pass server (c# / Razor) values into an AngularJS app

We use DNN and often need to pass a few context specific values (like page id or module-on-page-id) into an AngularJS app. We've developed our own conventions how to do this, but would like to hear from others how they approach this to find a best practice.
So basically the situation is that the server-page has information needed by the JS. Using WebAPI is not an option, as these values are known in the page, but not in a separate request. Things I've seen so far have been:
Use in-view-razor like href="#Tab.TabId/{{...}}" (I don't like this)
Place the values in the ng-init like ng-init="config = { prop1: '#Tab.TabId' }"
Create a separate <script> tag where we generate a module on the fly containing these values so angular.module("config", []).constant('prop1', '#Tab.TabId')
Create a json with razor in the page somewhere and inject all of it as a module into the app using a generic code which does the same as #3, just with cleaner code re-use.
I've seen all these and have also used all. Currently we avoid #1 as we believe it's not good to mix templating languages and because it doesn't allow externalizing parts of the view. So basically we use #2 as for quick-and-simple (and a bit dirty) + #3/#4 for larger projects.
Do you have a better way, or which way would you prefer?
We are using variant #4.
This has the advantage that the JSON defines the exact interface for the config needed by the JS module. And Razor is great to generate URLs using #Url.Action.
we use NewtonSoft and do JSONConvert.SerializeObject(ObjectName) and then pass it over as a Session from the controller and then use #Html.Raw(ObjectName) and its a JSON Object that can be utilized easily in javascript...

Integrating external files with AngularJs

I've just started using AngularJs.
I need to use the SunCalc module to calculate sun positions for my app.
I have no idea on how to integrate the file to the app and how to access his different functions while respecting the AngularJs structure. Where to put the file? How to call a function? etc...
Here is a link so you can quickly see the structure of the SunCalc module and hopefully help me.
https://github.com/mourner/suncalc/blob/master/suncalc.js
Thanks a lot for your help!
Since this library exposes global SunCalc object with bunch of methods, what you can do is simply wrap this lib into custom service.
app.factory('SunCalc', function() {
return window.SunCalc;
});
Then you could use it like this in controller:
app.controller('MainCtrl', function($scope, SunCalc) {
$scope.position = SunCalc.getTimes(new Date(), 52.3667, 4.9000);
});
In this case you can event add your own methods to this service without messing with original library.
Note, that technically you could use globally accessible SunCalc without creating one more service for this. However using services offers sertain advantages: you can rename it easily, it allows to facade original library API, using global variables error-prone, etc.
Also remember to include script tag before Angular script tag.
Demo: http://plnkr.co/edit/rbATLGfGE2kx32tmEEoX?p=preview

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;

Unique instances of Javascript self-executing anonymous functions

I have created the PHP side of a modular AJAX/PHP framework and now I am trying to implement the client side.
From my previous experience with modular web applications I know that sometimes multiple instances of one particular module are needed. For example, a web based two player game with page parts for each user.
On PHP side I have assigned a unque ID to each constructed instance of the module and I can pass this UID to the browser but I have no idea how to implement the Javascript side of this module instance.
Modules can be loaded all in one go or loaded separately through AJAX (I am using jQuery).
Now I am using a modular approach that I found in some article, but I can redesign it in some other way if that would help to solve this issue without sacrifising modularity and private/public code separation. For now let's say I have a js file with the following:
//Self-Executing Anonymous Func
(function( MyModule, $, undefined ) {
// My Uid
MyModule.UID = "";
//Public Method
MyModule.onLoad = function() {
alert("Hey, you loaded an instance of MyModule with UID " + MyModule.UID);
};
//Private Methods follow
function somethingPrivate( ) {
}
}( window.MyModule = window.MyModule|| {}, jQuery ));
I am using Smarty for templates. Let's say, I have a simple module template like this:
<div id="{$contents.moduleuid}">
here goes the contents of the module which can be accessed from MyModule Javascript code by using this unique moduleuid
</div>
I have set up the server side so each module automatically appends additional template with Javascript:
<script type="text/javascript">
/*
TODO: here I have access to the {$contents.moduleuid}
But I have no idea what to put here to create a unique instance of MyModule
(also it might need loading js file if it was not loaded yet) and I should also set for
this instance MyModule.UID to {$contents.moduleuid}
and also call MyModule.onLoad for this instance after it has loaded its Javascript.
*/
</script>
I am not experienced with advanced Javascript topics so it is unclear to me how I can create a separate instance of MyModule for each module which gets construced server-side? Is it possible at all to create instances of self-executing anonymous functions? If not, then how can I implement and clone Javascript objects with separated private/public code?
My recommendation is to keep the client side and server side loosely coupled. Try to build your modular client application completely with HTML/JS without PHP tricks on it. As I understand, each of your module (or UI component) need to be loosely coupled from the others. In such case there are several other concerns you might need to look for:
How to keep your UI component structure (html), presentation (css) and behavior (JS) self contained (for example in a single folder), so that it can live or die independently
How these self contained components interact with each other
How to manage the configurations/settings of your UI components
Should you be using MVVM or MVC pattern to organize and bind the view to your PHP model
Who decides when to create/show/hide your UI components (for example based on URL for bookmarking)
If your client is a large and complex application, you might need to look for other concerns such as JS optimization, unit testing, documentation, product sub modules, etc.
Have a look at the BoilerplateJS Javascript reference architecture we put forward at http://boilerplatejs.org. It suggests ways to address all concerns I discussed above.
Since you are already using jQuery, you could create a jQuery plugin. The plugin should behave the way you need, and I believe you won't even need a unique ID. Considering each of your module's instance is contained in a div with class module-container, your jQuery code for adding client-side behavior to the divs would be something like this:
$(function(){
// DOM content is loaded
$('.module-container').MyPluginName();
});
The minimal plugin code would be (considering it's in a separate .js file):
(function($){
$.fn.MyPluginName = function() {
// Return this.each to maintain chainability
return this.each(function() {
// Keep a reference to your unique div instance.
var $this = $(this);
// Plugin logic here
});
};
})(jQuery);
If you are using jQueryUI, I also recommend you also look into the "widget factory" (intro, docs), which serves as a base for building powerful, normalized jQuery plugins.

Categories

Resources