I've got some functions like this:
function killOrphans(str) {
return str.replace(/\s([\dwuioaz]{1})\s/gi, ' $1\u00a0');
}
which is generally a helper function to remove single letter words (orphans) from the end of a line (Polish typography demands to do this).
Question: how do you treat a library of such functions? A module in the global scope? extending jQuery? Extending the prototypes of String, Array etc.? (I don't think it's a good idea...). I think I'll go in the direction of underscore and create a module, but I'd be glad to hear real life examples of your way to do it.
Adam
In my project, I've used a variety of strategies for helper functions.
Extra methods on a view or a model.
var MyView = Backbone.View.extend({
initialize: function(){...},
render: function(){...},
helper: function(){...}
});
Use a helper module.
var myHelpers = {
foo: function(){...},
bar: function(){...},
baz: function(){...}
};
Extend an existing lib.
jQuery.fn.foo = function(){...};
Use an IIFE (best for functions you'd like to keep private)
var MyView = Backbone.View.extend({
initialize: function(){...},
render: function(){...},
myMethod: (function(){
function helper(){...}
return function(){
// do stuff here, using helper()
}
})()
});
Also, if you're not working in node.js which automatically provides a module system, it's worth using some strategy, such as browserify or requirejs, to export and import modules in a sane way, rather than having everything hang off the global namespace.
It is a question for Nobelprize - how to structure Javascript code with such a dynamic language. There are a lot of patterns and library solutions for this problem. For example:
You can extend prototype but then you are creating coupling. You can
create a module, but do you need module for one function ? You can
use Requirejs, annonymous functions...
Best real life examples are in production code. Take a look how jQuery deals with structure. And also Backbone. Try to learn classic design patterns - they are source of gold for any JS developer.
My advice is to dig deeper into JS and discover why language is designed in such a way. My first language was Javascript but I didn't make any progress until I started to learn something more traditional like in OO sense.
Related
How can I include a JavaScript file in my Angular project but assign a name to all of its functions? I just included Underscore.Script and Lodash for the first time and noticed they both have actual names ("_" and "s")..
_.mixin(s.exports());
I've watched a few courses on JavaScript and Angular but cannot find anything that actually explains this or how to accomplish it.
In Javascript, the simplest way is when writing your library define all of your functions as properties of an object in the global scope.
var myLibrary = {};
myLibrary.myFunction = function(){
/* Your function code */
};
Then after including your file, you can access your functions like so:
myLibrary.myFunction();
A better way might be to wrap your library in a self executing function, which will help you avoid unintentionally adding properties to the global scope (a good practice)
(function(root){
var myLibrary = {};
myLibrary.myFunction = function(){
/* Your function code */
};
root.myLibrary = myLibrary;
}(window));
Please note that passing window to the self-executing function will work in the browser, but not in a different context (like nodejs).
If you want to create something specifically for Angular, I would suggest looking into angular services which is how you can create libraries that work with the Angular dependency-injection system.
in angular we have controllers, directives, services, factories and providers.
Lets take an example of Factory - "Customer" having function to get and set details.
app.module.js
angular.module("myapp", []);
Customer.js
angular.module("myapp").factory("Customer", function(){
function Customer(name, email){
this.name = name;
this.email = email;
}
Customer.prototype.getName = function(){
return this.name;
};
Customer.prototype.getEmail = function(){
return this.email;
};
Customer.prototype.setName = function(name){
this.name = name;
};
Customer.prototype.setEmail = function(email){
this.email = email;
};
});
CustomerController.js
angular.module("myapp").controller("CustomerController", ['Customer',
function(Customer){
var custObj = new Customer();
custObj.setName("Test");
custObj.setEmail("test#gmail.com");
console.log("Name: " + custObj.getName() + " Email: " + custObj.getEmail());
}
]);
Here app.module.js -- Angular App main module is initialised.
Customer.js is a JS and you can use this file and its functions by giving it a name "Customer" in CustomerController.js file.
Other answers tell you to make your own scripts modular. This is good, but it doesn't solve the problem of disambiguating Underscore and LoDash. So here's how to do that:
I would first recommend that you look into modular systems like RequireJS. Libraries like LoDash and Underscore are built to recognize and integrate with AMD style architectures, allowing them to coexist (however, these two libraries are redundant. LoDash is supposed to be a drop-in replacement for Underscore. But I digress.
If you do not use a module system (not to be confused with angular's module), you'll have to do the shim work yourself. It isn't hard, by any means, but it's a bit manual. Scripts specified in your HTML are executed in-order (caveat: there are asynchronous loaders out there, but they make your problem easier to solve, not harder).
So, for your particular problem, you can do this:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.8.0/lodash.js"></script>
<script>
var mylodash = _;
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
<script>
var myunderscore = _;
</script>
You will thereafter have access to both (feel free to name or group them however you'd like). Both of these libraries do a good job of not polluting the global namespace (which is attached to window in a browser). But if your library exposes lots of different methods, you'll need to cobble them all together yourself.
Simple? Sure, but in the long run, learn to use something like CommonJS or RequireJS. They not only solve this particular problem, but they also provide so many other benefits -- you'll be glad you did.
tl:dr;
I want to consider the 'controller as' approach to simplify my inheritance process however I see some pitfalls around dependency injection and use in directives.
preface
I've been working on a pretty big Angular application for the last 6 months. I come from a more OOP language background but feel I've adapted fairly well to some of the quirkiness of javaScript and Angular.
With an application of this complexity, I think it necessitates great architectural solutions. I've elected to have baseController classes that UI controllers can inherit from using the current approach below.
current approach
All the current UI views/components/etc. are utilizing the $scope as the view model approach, aka. the classic approach. I achieved the controller inheritance like so:
NxBaseUiController
var NxBaseUiController = function($scope)
{
$scope.isLoggedIn = function(){}
$scope.doSomethingElse = function(){}
}
Here's a subclass base controller and it's inheritance
NxBaseListUiController
var NxBaseListUiController = function($scope)
{
var NxBaseUiController = require( './NxBaseUiController' )
NxBaseUiController.apply( this, arguments )
NxBaseListUiController .prototype = Object.create( NxBaseUiController.prototype );
$scope.query = require( './QueryModel' ).new()
}
What's crazy about this approach is that I'm having to maintain 2 series of inheritance all while keeping in mind of the existing NG scope inheritance that takes place in the view hierarchy. You can see this in the following UML diagram:
src - http://i.imgur.com/LNBhiVA.png
This all works so far, but moving onto a new section of the app, I want to start looking at the 'Controller As' syntax to see if there can be any simplification of the above approach.
questions
In all the examples I've seen of the 'controller as' approach, any methods attached are not defined on the prototype but rather the actual constructor like so:
function SomeController($scope)
{
this.foo = function(){};
}
Is there a reason why you wouldn't want to define the controller methods on the prototype?
The only reason I see attaching to the prototype as being problematic is you lose reference to your injected dependencies.
I realize I am coming at this from a very OO approach, however w/ an application of this size, being able to draw upon development patterns like inheritance seems necessary to solve code duplication.
Am I approaching this completely backwards? Are there any proven methods to achieving some semblance of inheritance in the controllers that doesn't require some wonky hack to work w/ the $scope?
There is no reason you can't use the prototype so long as you are OK with losing the ability to have actual private data vs having conventionally private data.
Let me explain with code:
function MyClass($http){
var privateData = 123,
$this = this;
$this.getAnswer = function(){
return privateData;
};
}
MyClass.$inject = ['$http'];
In that example you can't actually change privateData once the class has been instantiated.
function MyClass($http){
this._privateData = 123;
this.$http = $http;
}
MyClass.$inject = ['$http'];
MyClass.prototype = {
getAnswer: function(){
return this._privateData;
},
callHome: function(){
var _this = this;
_this.$http.get('/api/stuff')
.success(function(data){
_this.stuff = data;
});
}
};
In that example I am simply using a convention of prefixing my properties with an underscore (_) to signal that they should be treated as private.
Unless you are building a re-usable library however, this might not be a big deal.
Mind you some of this get's much simpler with ES6, so I would look into something like 6to5 or TypeScript if I were you. It might gel a little better with your OO background to write code like this:
//100% valid ES6
class MyClass extends BaseClass {
constructor(something){
super(something, 'foo');
}
someMethod(){
return this.foo;
}
}
I need to write a custom module for AngularJS, but I can't find any good documentation on the subject. How do I write a custom module for AngularJS that I can share with others?
In these situations were you think that the docs can't help you any more, a very good way to learn is to look at other already-build modules and see how others did it, how they designed the architecture and how they integrated them in their app.
After looking at what others did, you should have at least a starting point.
For example, take a look at any angular ui module and you will see many custom modules.
Some define just a single directive, while others define more stuff.
Like #nXqd said, the basic way to create a module is:
// 1. define the module and the other module dependencies (if any)
angular.module('myModuleName', ['dependency1', 'dependency2'])
// 2. set a constant
.constant('MODULE_VERSION', '0.0.3')
// 3. maybe set some defaults
.value('defaults', {
foo: 'bar'
})
// 4. define a module component
.factory('factoryName', function() {/* stuff here */})
// 5. define another module component
.directive('directiveName', function() {/* stuff here */})
;// and so on
After defining your module, it's very easy to add components to it (without having to store your module in a variable) :
// add a new component to your module
angular.module('myModuleName').controller('controllerName', function() {
/* more stuff here */
});
And the integration part is fairly simple: just add it as a dependency on your app module (here's how angular ui does it).
angular.module('myApp', ['myModuleName']);
If you want to look for a good example, you should look into the current module written in angularJS. Learn to read their source code. Btw this is a structure that I use to write modules in angularJS:
var firstModule = angular.module('firstModule', [])
firstModule.directive();
firstModule.controller();
// in your app.js, include the module
This is the basic one.
var newMod = angular.module('newMod', []);
newMod.controller('newCon', ['$scope', function ($scope) {
alert("I am in newCon");
$scope.gr = "Hello";
}]);
Here newMod is a module which has no dependencies [] and has a controller which has an alert telling you are in the controller and a variable with value hello.
I have a view that requires requires Backbone, Undescore, jquery etc.
example
define(['jquery','undescore','backbone','subviewA', 'subviewB'], function($,_,Backbone, SubviewA, SubviewB){
var View = Backbone.View.extend({
//other methods here
render : function() {
this.subviewA = new SubviewA();
this.subviewA.render();
this.subviewB = new SubviewB();
this.subviewB.render();
return this;
}
});
});
subview example
define(['jquery','undescore','backbone','text!templates/subviewA'], function($,_,Backbone, template){
var SubviewA = Backbone.View.extend({
//other methods here
render : function() {
this.$el.html(template);
return this;
}
});
});
My question is if I need to include jquery, undescore and backbone in the subviews too ir I can omit them?
EDIT
I am asking cause in r.js I need every time to tell it to not to biuld those dependencies inside each module.
Theoretically, if you don't use the $ or _ symbols in your views, you don't need to list jquery and underscore as direct dependencies of your module (whether it is a view or a subview doesn't change that).
You do need to include backbone though, since you reference it directly with : Backbone.View. If you want to be absolutely sure that the Backbone symbol is defined you should declare it as a dependency.
Some libs register themselves both as AMD modules and as global variables (typically jquery does that). Backbone doesn't support AMD directly and registers itself at the global level regardless of how it is used. In theory you could not declare it as a dependency, but then you have the risk that require will try and load the script before backbone is loaded in which case the Backbone symbol will not be defined.
It doesn't matter much if you redondantly declare the dependencies except for the additional caracters, thus the additional script size.
You can omit any requirements which aren't used.
In your examples (ignoring omitted code!), you can remove jquery and undescore (sic) but not backbone (since you use it via Backbone.View.extend).
Obviously you need to keep your requirement names and variables in sync.
I am unsure how I use namespaces in an modularized (RequireJs) Backbone environment.
I have thought a bit how it could look like but am totally unsure if this is the right way.
app.js (getting executed by main.js)
define('App', ['underscore', 'backbone', 'Router'], function( _, Backbone, Router){
function initialize(){
var app = {}; // app is the global namespace variable, every module exists in app
app.router = new Router(); // router gets registered
Backbone.history.start();
}
return { initialize: initialize }
});
messages.js
define('MessageModel', ['underscore', 'backbone', 'App'], function(_, Backbone, App){
App.Message.Model; // registering the Message namespace with the Model class
App.Message.Model = Backbone.Model.extend({
// the backbone stuff
});
return App;
});
Is this the right approach or am I fully on the wrong way (if yes please correct me!)
Have a look at the TODO Backbone + requireJs example:
https://github.com/addyosmani/todomvc
Found an real example app using namespaces like mentioned in the start post: https://github.com/nrabinowitz/gapvis
Just have to test it the next days
I'm new to backbone, but just read a snippet from the requirejs docs.
A module is different from a traditional script file in that it defines a well-scoped object that avoids polluting the global namespace. It can explicitly list its dependencies and get a handle on those dependencies without needing to refer to global objects, but instead receive the dependencies as arguments to the function that defines the module. Modules in RequireJS are an extension of the Module Pattern, with the benefit of not needing globals to refer to other modules.
To me, this sounds as if when using requirejs, you can forget all about namespaces, as requirejs takes care of it. You would just have access it differently. When you want to access it from another module, you'd put a path to the file in your array of dependencies, and and feed a respective variable to the following function.
define(["folder/a-script", "folder/another-script"], function(AScript, AnotherScript) {
// In here the scripts are loaded and can be used, but are called by
// their relative name in the anonymous function.
}
);
Anyway, perhaps in some cases there is still a need to namespace something, but I think in general, it's worth reading the docs to see if you need to.