We all know that decoupling is a good thing and the best way to do that when writing an application is to write libraries instead of application code.
What you can do now is to take parts of code that you have written, minimize it's dependancies and then generalize the input. Viola - a library that can be used in future projects.
Whenever I start a new project I try and identify parts of the program that can be abstracted, give it an API and make sure I don't pull in dependancies from elsewhere in the program (unless necessary and explicitly stated). Working like this helps decouple the project and stating dependancies and an interface will help future developers working on your project, but there are also more benefits.
Writing as a library will allow you to easily open-source non-critical parts of your project which can help the community, promote your company, and get feedback to improve the code. It also means that other people will be looking at your code which means you'll stay a bit more alert about writing good clean code, documentation and testing.
When working on your new library you may also put in extra functionality that isn't necessary in your project. This is good practice as it can help you in future iterations. I find sometimes I like to work on a library separate of a project to add in new features, only to then realize I can actually use these new features in the product. It's a win-win, and if you're using a minified like Closure-Compiler you won't have to worry about bloat as it removes unused functions.
The final reason is that it's a good abstraction. You might start writing out parts of the program only to realize that someone else has done a better job and because you started with a decoupled design it shouldn't be too hard to swap out for another library.
So next time you start on a new part of your program think about how you can generalize it, then stick it up on github.
Tuesday, May 29, 2012
Thursday, May 24, 2012
using JQuery functionally
I was looking at the code on a site recently and it was all blocks of JQuery. The first thing I saw was that there was a lot of lines that were almost the same - basically that there was a selector then 3-4 methods chained off it. First thing I thought was why not put that in a function, something like:
which would allow you just to call the doStuff method with the selector. It then hit me that we're just abstracting away the functionality of JQuery which is a good thing. Then I wondered if I could change it in to functional style (without writing the whole of JQuery).
The first thing is to realize is that Javascript allows us to change scope using call or apply. You can pretty much write OO code in a functional style using those. So basically these are the same:
Now JQuery makes it easy to get to it's prototype for adding plugins. This mean we can call a jquery method like:
Ah, now we can see that the $() is a function itself. So now we can use composition f.g(x) == f(g(x)):
There is still a problem though, compose will call the method with a different context and pass in the JQuery object as the first argument. There are two solutions and they're both fairly useful. The first is that we could have a special bind for JQuery methods:
so we could bind the method and pass it in to compose or even just use it:
The major difference is that $bind will take in other arguments when bound, whereas compose methods only accept one argument.
But we can probably do on better. We could just check to see if it's a jquery function and apply it inside compose. So let's make $compose:
Now we can just pass in the jquery methods to compose as they are. So let's compare:
So there we have it. JQuery being used functionally. I haven't tested or tried any of the code so not sure if it will just work but hopefully it's enough to get you interested and I'd love to see what other people can do with it. Keep in mind though that compose functions take one argument so it's great for things like $.fn.hide but you may want to bind other methods:
You may want to make some improvements in $bind and $compose like automatically wrap whatever is passed in with the JQuery object.
var doStuff = function(selector) {
$(selector).method1().method2().method3();
};
which would allow you just to call the doStuff method with the selector. It then hit me that we're just abstracting away the functionality of JQuery which is a good thing. Then I wondered if I could change it in to functional style (without writing the whole of JQuery).
The first thing is to realize is that Javascript allows us to change scope using call or apply. You can pretty much write OO code in a functional style using those. So basically these are the same:
// OO
obj.method(param);
// Functional
Obj.prototype.method.call(obj, param);
Now JQuery makes it easy to get to it's prototype for adding plugins. This mean we can call a jquery method like:
$.fn.method.call($(selector));
Ah, now we can see that the $() is a function itself. So now we can use composition f.g(x) == f(g(x)):
compose($.fn.method, $)(selector);
There is still a problem though, compose will call the method with a different context and pass in the JQuery object as the first argument. There are two solutions and they're both fairly useful. The first is that we could have a special bind for JQuery methods:
var $bind = function(fn) {
var args = arguments;
return function($object) {
return fn.apply($object, args.splice(1));
};
};
so we could bind the method and pass it in to compose or even just use it:
var $method = $bind(method);
var $elems = $(selector);
$method($elems);
// or
compose($method, $)(selector);
The major difference is that $bind will take in other arguments when bound, whereas compose methods only accept one argument.
But we can probably do on better. We could just check to see if it's a jquery function and apply it inside compose. So let's make $compose:
var $compose = function(var_args) {
var args = [].slice.call(arguments);
return function(arg) {
var ret = arg;
for (var i = args.length; i; i--) {
if(args[i - 1] in JQuery.fn)
ret = $bind(args[i - 1])(ret);
else
ret = args[i - 1](ret);
}
return ret;
};
};
Now we can just pass in the jquery methods to compose as they are. So let's compare:
// OO style
var doStuff = function(selector) {
$(selector).method1().method2().method3();
};
doStuff(selector);
// Functional style
var doStuff = $compose($.fn.method3, $.fn.method2, $.fn.method1, $);
doStuff(selector);
So there we have it. JQuery being used functionally. I haven't tested or tried any of the code so not sure if it will just work but hopefully it's enough to get you interested and I'd love to see what other people can do with it. Keep in mind though that compose functions take one argument so it's great for things like $.fn.hide but you may want to bind other methods:
var makeRed = $bind($.fn.css, {'background': 'red'});
compose(makeRed, $)(selector);
You may want to make some improvements in $bind and $compose like automatically wrap whatever is passed in with the JQuery object.
Thursday, May 17, 2012
Starting Closure
There has never been a better time to start using Closure.
The closure set of tools has been open sourced for a couple of years now and the last piece of the puzzle has landed, namely Closure Stylesheets. Now there is a full set of tools that are out there for you to use, not only that but the tools have been out long enough that there is help available.
Closure tools has been created fir a large team to create large applications. This has been the main hurdle to new developers wanting to learn. Most new developers will begin to learn closure at work in a team. Luckily there are now tools out there to help single programmers start for any size of project. Here is what you need to start:
The closure set of tools has been open sourced for a couple of years now and the last piece of the puzzle has landed, namely Closure Stylesheets. Now there is a full set of tools that are out there for you to use, not only that but the tools have been out long enough that there is help available.
Closure tools has been created fir a large team to create large applications. This has been the main hurdle to new developers wanting to learn. Most new developers will begin to learn closure at work in a team. Luckily there are now tools out there to help single programmers start for any size of project. Here is what you need to start:
Closure: The definitive guide
If you want to start with the tolls a great way to start is to understand the thinking behind it. The book will give great insights in to how the tools work and how you can use them. There are great books out there for every library, and closure is no exception.Plovr
Plovr is a tool written by Michael Bolin and makes using the library, compiler, templates and tests a breeze.
G-Closure
I'm guessing you already know jquery. Let's face it, it's almost analogous to javascript. One of the concerns that people have is that the closure library is long-winded. The library was written in a functional style and namespaced so you have to type out the namespace then the function and pass in the object you need. JQuery is a bit easier as you already have the object and you can just call functions on that, not only that but you have the famous chaining API. G-Closure lets you use DOM, Array and Object functions in the closure-library like you would JQuery. This means you don't even need to know the library to start, if you know jquery you can already build a webpage using the library.
PlastronJS
You probably use backbone.js or some other MVC. Well now closure tools has an MVC too, PlastronJS. If you read this blog you should know all about it by now. It's designed to be familiar but also, like the closure library, have many more features you can choose to call on or disregard depending on your needs.
Et al.
An honorable mention should go towards the closure coffeescript fork which does a great job removing the "wordiness" of the library.
But Wait!
If you were about to go hop off and try Closure Tools for the first time I recommend waiting just a little bit more. Closure Tools now has a meetup which means the community is going to get stronger and the toolset is going to get easier. In fact I'll have another little project to announce very soon that should help you on your way. In the meantime I recommend starting by reading the book and keeping your eyes peeled on this blog for further announcements.
Wednesday, May 16, 2012
Functional Closure
When you look at it, the closure library is perfect for functional style programming. The whole library is given to you as functions rather than methods that have to be put on objects.
Unfortunately it is lacking though. goog.bind and goog.partial only get us some of the way and there could be a better way to do it. That's why I'm happy to introduce Functional Closure which will help all your dreams come true (well, at least help you in your functional style efforts).
The main function in functional closure is func.curry. This will not only allow you to partially apply only the variables you select but will also return a function that will continue to curry itself until you tell it to stop. You can also set a minimum number of inputs which when passed will give you back a value.
So how does it work? say we want to find the maximum of 10 numbers. We can curry Math.max like so:
You can also not pass a minimum to just keep returning the curry until you call it with no arguments.
Great, now what else does it have? Well now we have curry we might want another way to curry the right arguments. Here we have func.flip. Say you want to map something that will increment the number, you can flip around the closure libraries array functions to do that for you:
Want even more? Well the library already has these made for you. You can just use func.map which is already curried so the above is equivalent to:
There are a range of functions you can use - checkout the read me for more information.
Great, how about point-free style? Well we've got that covered to. func.compose will let you join up functions the way you want to. For instance let's say I want a filter function that will look at the models of an object and see if they're not in an array of existing models:
WOAH! slow down there, what happened? Well most the 'func' functions can also take strings and convert them to functions. If you want a simple lambda that's a single line just write it with x as the input and it will return the result.
Want to learn more? Checkout the github repository. The library is built to run with closure tools and is built with inspiration from functional javascript and http://drboolean.tumblr.com/
Unfortunately it is lacking though. goog.bind and goog.partial only get us some of the way and there could be a better way to do it. That's why I'm happy to introduce Functional Closure which will help all your dreams come true (well, at least help you in your functional style efforts).
The main function in functional closure is func.curry. This will not only allow you to partially apply only the variables you select but will also return a function that will continue to curry itself until you tell it to stop. You can also set a minimum number of inputs which when passed will give you back a value.
So how does it work? say we want to find the maximum of 10 numbers. We can curry Math.max like so:
var max = func.curry(Math.max, 10);
max = max(1,2,3); // we can pass in any number of values at a time
max = max(undefined, 5); // we can pass in undefined to skip a value
max = max(4)(6)(7); // you can pass in values like this (the 4 will be used where the undefined was put)
second = max(8) // the curry returns a new function you can assign to another function
second(); // 8 - passing no arguments will execute the function as it stands
max(8, 9, 10, 11, 12); // 12 - once you pass the minimum passed in you get a result
You can also not pass a minimum to just keep returning the curry until you call it with no arguments.
Great, now what else does it have? Well now we have curry we might want another way to curry the right arguments. Here we have func.flip. Say you want to map something that will increment the number, you can flip around the closure libraries array functions to do that for you:
var addOneToAll = func.curry(func.flip(goog.array.map), 2)(function(a) {return a+1;});
Want even more? Well the library already has these made for you. You can just use func.map which is already curried so the above is equivalent to:
var addOneToAll = func.map(function(a) {return a+1;});
There are a range of functions you can use - checkout the read me for more information.
Great, how about point-free style? Well we've got that covered to. func.compose will let you join up functions the way you want to. For instance let's say I want a filter function that will look at the models of an object and see if they're not in an array of existing models:
var notInModels = func.compose('!x', func.isIn(models), 'x.getModel()');
WOAH! slow down there, what happened? Well most the 'func' functions can also take strings and convert them to functions. If you want a simple lambda that's a single line just write it with x as the input and it will return the result.
Want to learn more? Checkout the github repository. The library is built to run with closure tools and is built with inspiration from functional javascript and http://drboolean.tumblr.com/
Sunday, May 13, 2012
PlastronJS - the todomvc example walkthrough
A walkthrough of the code for the PlastronJS TodoMVC example
Dot vs square bracket notations in Closure
In javascript you can use square brackets and dot notation almost interchangeably:
Which is great and you can do things like:
so you can then put getters on an object (in this case A). e.g:
There are some other great uses as well such as the delegateEvents in backbone.js
But unfortunately in closure we can't do this because after compilation:
This is because string literals will not be compiled, but properties with dot notation will be renamed. Fear not however because we don't actually need to mix these two and it does help if you think about these not being the same.
If you have a look at plastronjs you'll notice that setting a schema will look like:
so the properties have strings and the get and set don't. Closure will rename strings but not properties. The reason they are like this is that property will be called on using model.set() and model.get() that take a string as the first argument and those can either be sent or received through a sync. So basically prop1 and prop2 can be EXTERNAL. get and set are only ever used inside our program so they are INTERNAL.
so how about the options object that gets passed to a model? it takes:
'attr', 'sync', 'schema' etc. Why are those in quotes? Well the fact is that I've allowed you to just pass through ordinary properties at the top level, so who is to say when those are compiled (sat attr -> a) that you haven't defined 'a' as a property? I'm allowing you to mix external and internals so to be safe I have to use the quotes. In doing that I then have to refer to the options object for object['attr'] instead of object.attr so we're losing a little compiled space but making things much easier to pass through attributes.
Just to make things easier I've also given you a special method in mvc.Model which will allow you to get around typing the string every time you need an attribute. What we can do is bind a function to that attribute to make things easier. Say we have an attribute 'star' that is either true or false. If I reuse it a lot, instead of doing model.get('star') I'd like something a bit easier. mvc.Model#getBinder to the rescue. Now you can do this:
The getBinder method is simple and looks like this:
It will allow you to get and set through a function whose name can be compiled and also makes it easy to call.
So what is the moral of the story? Well there are three:
Keep these in mind when you start and after a bit of practice you won't miss being able to mix notations, and it will certainly help you keep down differences between the compiled and uncompiled versions of your code.
a['property'] === a.property
Which is great and you can do things like:
function createGet(property, fn) { A['get'+property] = fn(A[property]); }
so you can then put getters on an object (in this case A). e.g:
A.one = 1; A.two = 2; var sayNumber = function(num) {return "number is: " + num;}; createGet('one', sayNumber); createGet('two', sayNumber); A.getOne(); // "number is : 1" A.getTwo(); // "number is : 2"
There are some other great uses as well such as the delegateEvents in backbone.js
But unfortunately in closure we can't do this because after compilation:
a['property'] !== a.property
This is because string literals will not be compiled, but properties with dot notation will be renamed. Fear not however because we don't actually need to mix these two and it does help if you think about these not being the same.
If you have a look at plastronjs you'll notice that setting a schema will look like:
var schema = { 'prop1' : { get: function ... set: function ... }, 'prop2' : { get: function ... set: function ... } };
so the properties have strings and the get and set don't. Closure will rename strings but not properties. The reason they are like this is that property will be called on using model.set() and model.get() that take a string as the first argument and those can either be sent or received through a sync. So basically prop1 and prop2 can be EXTERNAL. get and set are only ever used inside our program so they are INTERNAL.
so how about the options object that gets passed to a model? it takes:
'attr', 'sync', 'schema' etc. Why are those in quotes? Well the fact is that I've allowed you to just pass through ordinary properties at the top level, so who is to say when those are compiled (sat attr -> a) that you haven't defined 'a' as a property? I'm allowing you to mix external and internals so to be safe I have to use the quotes. In doing that I then have to refer to the options object for object['attr'] instead of object.attr so we're losing a little compiled space but making things much easier to pass through attributes.
Just to make things easier I've also given you a special method in mvc.Model which will allow you to get around typing the string every time you need an attribute. What we can do is bind a function to that attribute to make things easier. Say we have an attribute 'star' that is either true or false. If I reuse it a lot, instead of doing model.get('star') I'd like something a bit easier. mvc.Model#getBinder to the rescue. Now you can do this:
var star = model.getBinder('star'); star(); // true star(false); star(); // false
The getBinder method is simple and looks like this:
mvc.Model.prototype.getBinder = function(key) { return goog.bind(function(val) { if (goog.isDef(val)) { this.set(key, val); } else { return this.get(key); } }, this); };
It will allow you to get and set through a function whose name can be compiled and also makes it easy to call.
So what is the moral of the story? Well there are three:
- If a property is visible externally or is mixed with external properties that use square brackets
- If a property is internal only to the project then use dot
- If you're using a lot of square brackets think about binding it to a function
Keep these in mind when you start and after a bit of practice you won't miss being able to mix notations, and it will certainly help you keep down differences between the compiled and uncompiled versions of your code.
Saturday, May 12, 2012
TodoMVC PlastronJS example
Here is a run through of how to get the todoMVC example, checkout the uncompiled code and how to compile changes you make.
If you're having trouble seeing the characters try clicking the youtube button on the video and watching it in fullscreen.
Wednesday, May 9, 2012
Functional Javascript
There's been a bit of buzz about Functional javascript lately. It's easy to see why as javascript is such a flexible language that you can use it in both the functional and Imperative style. When I talk about functional style I'll mostly be referencing a style called point-free.
I'm a big advocate of the Closure Library and believe it will port well over to the functional style - even though it hasn't got all the right tools... yet.
So just what is the difference? Well Functional style is made up of functions (thus the name) and not objects. An object is something that has state (this "this" variables) and this is the enemy of the pure function. A pure function is what you strive for in a functional language and it's a pretty simple thing. A pure function is a function that when given an input will always return the same output for that input with no side effects. e.g:
now these functions are similar... until someone changes a. even if you change a (a = x) it is impure because now it has a side-effect (a is changed).
So why do we like pure functions? several reasons:
Unfortunately the running in parallel doesn't really help us yet, but eventually javascript engines may be able to realize when a function is pure and run it. For example take the .map() function that runs a function on each element. If we know that function is pure we know that each function will not change the output on the next variable - so each map function can safely be run in parallel. If that function changes state however and the function uses that state for the output then we have to run them sequentially as the function needs to know what the state has changed to.
Right so pure functions are good, why can't we use them in the imperial style then? Well the fact is you probably already are. things like .map() .filter() and other new array functions come from functional style. Concepts also like partial application and currying are also from functional style. So we're already starting to use some concepts today.
So is there any more cool stuff we can use? Sure. Plenty. Function composition. In fact underscore has a nice little function that allows you to use it. What function composition allows you to do is chain together functions to create a single function you can use.
I hope that has whetted your appetite a little. I'll probably go over some more in later posts but for now there is more you can do learn. First check out this talk and visit the links. Teach yourself Haskell with a good book and stay tuned.
I'm a big advocate of the Closure Library and believe it will port well over to the functional style - even though it hasn't got all the right tools... yet.
So just what is the difference? Well Functional style is made up of functions (thus the name) and not objects. An object is something that has state (this "this" variables) and this is the enemy of the pure function. A pure function is what you strive for in a functional language and it's a pretty simple thing. A pure function is a function that when given an input will always return the same output for that input with no side effects. e.g:
// Pure function: function pure(x) {return x;} // Not a pure function: var a = 0; function impure(x) {return x+a};
now these functions are similar... until someone changes a. even if you change a (a = x) it is impure because now it has a side-effect (a is changed).
So why do we like pure functions? several reasons:
- Pure function outputs can be memorized (as the same input gives the same output)
- Pure functions are easy to test (no having to text different states)
- Pure function allows code to run in parallel
Unfortunately the running in parallel doesn't really help us yet, but eventually javascript engines may be able to realize when a function is pure and run it. For example take the .map() function that runs a function on each element. If we know that function is pure we know that each function will not change the output on the next variable - so each map function can safely be run in parallel. If that function changes state however and the function uses that state for the output then we have to run them sequentially as the function needs to know what the state has changed to.
Right so pure functions are good, why can't we use them in the imperial style then? Well the fact is you probably already are. things like .map() .filter() and other new array functions come from functional style. Concepts also like partial application and currying are also from functional style. So we're already starting to use some concepts today.
So is there any more cool stuff we can use? Sure. Plenty. Function composition. In fact underscore has a nice little function that allows you to use it. What function composition allows you to do is chain together functions to create a single function you can use.
I hope that has whetted your appetite a little. I'll probably go over some more in later posts but for now there is more you can do learn. First check out this talk and visit the links. Teach yourself Haskell with a good book and stay tuned.
Tuesday, May 8, 2012
how to display a collection
There are two options when displaying a collection of controls, both with their drawbacks.
Refresh
The easiest one to master is the refresh. All you need to do is listen to any change to the collection then scrap all the child controls and re-render new ones. It's simple and means that your child controls won't need listeners on the models to change presentation - instead you can put logic in your templates to display the control with the model's current state.
This is the approach I've taken with the todomvc. It uses a lot less code (in fact compiled it is the smallest example on the entire site including the pure closure example - and it includes extra feats like routing!) and is pretty efficient for small lists. It can be slow though as it removes all the controls first and re-renders them and can cause memory leaks.
You should be cleaning up listeners on elements every time you remove a control. Luckily the closure library uses good.ui.component and automatically will cleanup listeners for you when you call dispose(). This wonderful mechanism has been used by mvc.Control so anytime you call a this.on, this.click, this.bind, etc. the handler is registered on the control and will be removed when you call mvc.Control#dispose().
Pretty neat eh? So PlastronJS has all the mechanisms you need to make this happen. It can cleanup for you on the refresh and can listen to any changes on a child that need you to refresh (anyModelChange).
Individual Updates
Now to the tricky part. What happens if you have complex child controls? well PlastronJS helps you with this as well. the collection has a listener for modelChange which only fires when the shape of the children change. Now what do I mean by shape?
The shape of the children refers to changes in sort order, or adding or removing children. If you want you can think of it as comparing an array of just the child model ids. So if you update a child but the list order doesn't change then modelChange will not fire. This means no re-rendering the entire list just for one small change.
But this comes at the price of complexity. The child models now have to manage their own display with listeners on their models. You will also need to write a function to run through the controls children and match the existing controls with it's collections child models, but what it means is less changes to the DOM and a faster site.
The truth is it can be complex managing this - (what happens if the child control disposes itself? how should you shuffle around the resorted nodes?) and as yet PlastronJS leaves you with the details.
In the next iteration though I'm planning some way of letting you attach what a child control should look like and have PlastronJS deal with the shape changes by moving controls in the least amount of steps. This will probably come as a new mvc.ListControl that inherits from mvc.Control so stay tuned!
Principles of an MVC design
One of the things that I had to figure out when first using an MVC design was how things slot together. You have collections of models and collections of controls that all fit together somehow and you also have all the dependancies and listeners between them.
One of the things I disagree with in Backbone.js is the way a model has a link to it's collection. To me it felt like spaghetti code, why should an individual model need access to it's collection? It doesn't and this is one of the things that I baked in to PlastronJS.
I'm guessing this link was given so when a change was made to the model you could then pass the change up to it's collection - but this means the model knows it is in a collection. Instead in PlastronJS the collection will register handlers on each new model connected to it and so the collection model is in charge of it's changes and the model only deals with it's own. But how do you pass changes across? You do it in the control.
If you have a look at my todomvc example I have listeners on modelChange and anyModelChange which are fired by the collection when it's listeners on it's models are fired. Because it knows there is a change it can then do the calculations that are needed without having the models in the collection have an explicit link to it's collection.
This is the fundamental idea behind the interaction with the MVC. The user interacts with the view which is listened to by the control. The control then changes the model which alerts anything listening to it. So if I have a completed count on the list and the user ticks a completed button the interaction goes like this:
user click completed on view -> control listener executes and changes the model -> the model changes and alerts all listeners -> the collection which has a listener on that model fires a change event -> the control for the list picks up the event from the collection and updates it's view
As you can see all interactions should go from the view down to the model and back up to the view. Which leads to 2 basic rules when setting up event listeners in a control:
One of the things I disagree with in Backbone.js is the way a model has a link to it's collection. To me it felt like spaghetti code, why should an individual model need access to it's collection? It doesn't and this is one of the things that I baked in to PlastronJS.
I'm guessing this link was given so when a change was made to the model you could then pass the change up to it's collection - but this means the model knows it is in a collection. Instead in PlastronJS the collection will register handlers on each new model connected to it and so the collection model is in charge of it's changes and the model only deals with it's own. But how do you pass changes across? You do it in the control.
If you have a look at my todomvc example I have listeners on modelChange and anyModelChange which are fired by the collection when it's listeners on it's models are fired. Because it knows there is a change it can then do the calculations that are needed without having the models in the collection have an explicit link to it's collection.
This is the fundamental idea behind the interaction with the MVC. The user interacts with the view which is listened to by the control. The control then changes the model which alerts anything listening to it. So if I have a completed count on the list and the user ticks a completed button the interaction goes like this:
user click completed on view -> control listener executes and changes the model -> the model changes and alerts all listeners -> the collection which has a listener on that model fires a change event -> the control for the list picks up the event from the collection and updates it's view
As you can see all interactions should go from the view down to the model and back up to the view. Which leads to 2 basic rules when setting up event listeners in a control:
- listeners on the view should only update the model
- listeners on the model should update the view
There may be times when you want a change in a model to update another model, but I like to think of this as linking up the two models separately and should be done outside of a controller.
The reason to stick to this is simple - you don't want to repeat yourself. If you want to put a class "done" on an object when a checkbox is clicked and change the model to complete you don't want to do both on clicking the checkbox. For this you need two listeners, one that sets the model to complete when the checkbox is checked and a listener on the model that will set the class when it's checked attribute is set. That means that any new interactions you put in will automagically set the done class (say if later you want that item to be shared and can get updated in realtime through a web socket or long polling).
Stick to those rules and you'll write less code, more flexible code and just plain better code.
Now how about when you click a "select all" in the collection's control? Easy, the collection's control should have a reference to all the children controls and pass along the call to them to set it's model as completed.
You can also do things like have a child set itself as the only one to complete by passing up to it's parent (this is allowed because they are controls - not models - and live in a definite tree structure on the page) itself and have the collection have a setOnlyChildComplete() method which could go through it's own children and only set the given one to complete.
Javascript Gentleman Rule #3: Lint
We're all human and humans make mistakes.
You may not be perfect but you can make sure your code is by using linters. A tool will make sure that your code and everyone else in your team has code that reads the same.
There are three choices for javascript:
You may not be perfect but you can make sure your code is by using linters. A tool will make sure that your code and everyone else in your team has code that reads the same.
There are three choices for javascript:
For Coffeescript:
For CSS:
Wednesday, May 2, 2012
Closure Stylesheets (GSS) in sublime text2
Should also work in Textmate, I've copied the CSS package and edited it to give syntax highlighting for .gss files here:
https://github.com/rhysbrettbowen/gss.sublime-package
You should create a new folder under Packages (you can get there by going to the sublime text 2 menu -> preferences -> Browse Packages....) called "GSS". Restart sublime text and away you go. So far there is highlighting for:
@def
@defmixin
@mixin
uppercase variables (hopefully you're only using uppercase for variables)
functions (both CSS function and @mixin functions)
@defmixin function variables
Any feedback about improvements would be great!
https://github.com/rhysbrettbowen/gss.sublime-package
You should create a new folder under Packages (you can get there by going to the sublime text 2 menu -> preferences -> Browse Packages....) called "GSS". Restart sublime text and away you go. So far there is highlighting for:
@def
@defmixin
@mixin
uppercase variables (hopefully you're only using uppercase for variables)
functions (both CSS function and @mixin functions)
@defmixin function variables
Any feedback about improvements would be great!
Subscribe to:
Posts (Atom)