#Ebauche d'un framework MVC (Client) en Dart
##Installation
- Téléchargement : http://www.dartlang.org/docs/editor/getting-started/#download
##Créer un 1er projet
Nommer le projet "cubitus", modifier cubitus.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cubitus</title>
<link rel="stylesheet" href="cubitus.css">
</head>
<body>
<p></p>
<script type="application/dart" src="cubitus.dart"></script>
<script src="http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
</body>
</html>
##Créer une librairie
C'est un fichier .dart
avec une déclaration en en-tête de code : #library("nom_de_la_librairie")
. Ensuite pour la référencer dans un code source, on utilise : #import("chemin_et_nom_du_fichier_dart_de_la_librairie")
.
###cubitus.mvc.dart et 1ère classe "Model"
Créez un fichier cubitus.mvc.dart
avec le code ci-dessous. Notre classe Model
ne fait pas grand chose, si ce n'est recevoir une map d'attributs comme paramètre du constructeur, et avoir 2 méthodes pour affecter ou récupérer la valeur d'un attribut ("à la" Backbone) :
#library("cubitusmvc");
#import('dart:json');
class Model {
Map attributes;
//Constructeur
Model(this.attributes) {
}
Object get(String attributeName) {
return this.attributes[attributeName];
}
void set(String attributeName, Object value) {
this.attributes[attributeName] = value;
}
String toJSON() {
return JSON.stringify(this.attributes);
}
}
##1ère Utilisation de notre librairie
Dans le fichier principal cubitus.dart
:
#import('dart:html');
#import('cubitus.mvc.dart');
class Human extends Model {
Human(attrs) : super(attrs) {}
}
void main() {
var p = query("p");
var bob = new Human({"firstName":"Bob", "lastName":"Morane"});
print(bob.toJSON());
bob.set("firstName","Bobby");
print(bob.toJSON());
p.innerHTML = """
<b>FirstName : </b>${bob.get("firstName")}<br>
<b>LastName : </b>${bob.get("lastName")}
""";
}
##Ajoutons une classe View à notre librairie cubitus.mvc.dart
Tout d'abord ajouter #import('dart:html');
, puis le code de la classe View
:
class View {
Element e;
String tpl;
View(this.e) { }
render() {
this.e.innerHTML = this.tpl;
}
}
###Utilisation de notre vue :
Dans le fichier principal cubitus.dart
:
#import('dart:html');
#import('cubitus.mvc.dart');
class Human extends Model {
Human(attrs) : super(attrs) {}
sayHello() {
print(this.toJSON());
}
}
class HumanView extends View {
HumanView(el) : super(el) {}
View useSingleModelTemplate(Model data) {
this.tpl = """
<b>FirstName : </b>${data.get("firstName")}<br>
<b>LastName : </b>${data.get("lastName")}
""";
return this;
}
}
void main() {
var p = query("p");
var bob = new Human({"firstName":"Bob", "lastName":"Morane"});
var humanView = new HumanView(p);
bob.set("firstName","Bobby");
humanView.useSingleModelTemplate(bob).render();
}
##Collection (à la Backbone) et encore View
Dans cubitus.mvc.dart
, ajouter :
class Models {
List list;
Models(this.list){ }
List getList() {
return this.list;
}
Models add(Model model) {
this.list.add(model);
return this;
}
}
###Utilisation
Dans cubitus.html
ajouter <ul></ul>
après <p></p>
, puis dans le fichier principal cubitus.dart
:
Créer une class Humans
qui hérite de Models
:
class Humans extends Models {
Humans(list) : super(list) {}
}
Modifier la vue HumanView
en lui ajoutant une méthode useSeveralModelsTemplate
:
class HumanView extends View {
HumanView(el) : super(el) {}
View useSingleModelTemplate(Model data) {
this.tpl = """
<b>FirstName : </b>${data.get("firstName")}<br>
<b>LastName : </b>${data.get("lastName")}
""";
return this;
}
View useSeveralModelsTemplate(Models data) {
var html = new StringBuffer();
data.getList().forEach((model) =>
html.add("<li>${model.get("firstName")} ${model.get("lastName")}</li>"));
this.tpl = html.toString();
return this;
}
}
####Utiliser :
Dans main() { ... }
:
var humansList = new Humans([bob, sam, john]);
var u = query("ul");
var humansView = new HumanView(u);
humansView.useSeveralModelsTemplate(humansList).render();
##Le routeur "Router"
Nous allons faire très simple (pas de passage de paramètre dans l'url), dans cubitus.mvc.dart
, ajouter :
class Router {
Map routes;
Router(this.routes) {
window.on.popState.add((event) {
var tmp = window.location.toString().split("#");
if(tmp.length > 1) {
print(tmp[1]);
this.routes[tmp[1]]();
} else {
//root
this.routes["root"]();
}
});
}
}
##Utiliser notre routeur
Changer le code de main()
dans cubitus.dart
par :
void main() {
var p = query("p")
, u = query("ul")
, bob = new Human({"firstName":"Bob", "lastName":"Morane"})
, sam = new Human({"firstName":"Sam", "lastName":"LePirate"})
, john = new Human({"firstName":"John", "lastName":"Doe"})
, humansList = new Humans([bob, sam, john])
, humanView = new HumanView(p)
, humansView = new HumanView(u)
, router;
router = new Router({
"/display/all" : () => humansView.useSeveralModelsTemplate(humansList).render(),
"/display/bob" : () => humanView.useSingleModelTemplate(bob).render(),
"root" : () => p.innerHTML = "<h1>Welcome !!!</h1>"
});
}
##Conclusion
Je trouve Dart intéressant et agréable à utiliser, probablement plus "cadré" que Javascript, mais si on fait un effort, on peut faire autant de c... en Dart qu'en Javascript (vous remarquerez que même si elles existent, je n'ai pas eu besoin d'interface par exemple et je peux indifférement utiliser Model ou Human même si elles ont des signatures différentes).
Je vais continuer à creuser, mais pour le moment ma préférence reste à Javascript. Il n'y a pas d'interopérabilité entre Dart et Javascript et c'est un peu dommage. J'aurais préféré un système façon Coffeescript avec des accolades ;).