Le 18/08/2015
Pierre Besson
//Egalité
1 == '1' //=> true
1 === '1' // => false
//Toujours privilégier la triple égalité
// Une fonction JS a un contexte qui lui est propre. Ce contexte se retrouve dans le this.
// Un problème fréquent en JS est le problème de la closure qui correspond à une perte de contexte.
// Ce qu'il faut retenir: quand vous avez un this qui n'est pas correct dans une fonction, il s'agit d'un problème de closure.
const a = ["E1", "E3","E4","E5"];
for(var i=0, aLength = a.length; i< aLength ; i++){
window.setTimeout(
function(){console.log('noClosure', i);}
,1000);
//Closure
window.setTimeout(
(function(p){
return console.log('closure', p);
})(i)
, 1000);
}
// Une Promise permet d'effectuer un traitement asynchrone de manière très lisible
let asyncTreatement = require('../mySuperSvc');
asyncTreatement.then(function success(d){
treatSuccess(d);
}, function error(e){
treatError(e);
});
Text
promise.then(successCb,errorCb).then(otherSuccess, otherCb)//Service de chargement
function loadGodsSvc(){
return Promise.resolve([
{nom: 'Zeus', ctcId: 1},
{nom: 'Hades', ctcId: 2},
{nom: 'Poseidon', ctcId: 3},
]);
}
//Ce qui nous intéresse c'est de transformer l'information pour avoir un id plutôt qu'un ctcId.
function traitement(){
loadGodsSvc().then((data)=>{
return data.map((god)=>{
let {nom, ctcId} = god;
return {
name: nom,
id: ctcId
};
});
});
}
//On récupère dans une promesse l'objet suivant
// [{id: 1, name: 'Zeus'} ,...]Nous utilisons CommonJS dans le projet
Chaque fichier est un module qui est un singleton.
Afin de rendre public un contenu il suffit d'utiliser le mot clef:
module.exports = {mySuperObjectToExportOrFunction}
Exercice: https://gist.github.com/pierr/3a2f5a7e3f505b25c961
https://github.com/lukehoban/es6features#arrows
//On a un objet de la forme
var obj = {
prenom: 'Pierre',
nom: 'Besson'
age: 27,
adresse: "12 rue des fleurs 75000 Paris FRANCE"
};
//On s'intéresse à prénom et age uniquement
//ES5
var nom = obj.nom;
var prenom = obj.prenom;
//ES2015
let {nom, prenom} = obj;//ES5
var bjr = 'Bonjour';
var name = 'focus';
var str = bjr + ' '+ name+ ' !'
// Bonjour focus !
//ES6
let bjr = 'Bonjour';
let name = 'focus';
let str = `${bjr} ${name} !'
// Bonjour focus !
//ES5
var mySuperMixin = {
displayName: 'Pierre',
displayBonjour: function displaybonjour(){
console.log('super fonction');
}
};
//ES6
var mySuperMixin = {
displayName: 'Pierre',
displayBonjour(){
console.log('super fonction');
}
};// Expression bodies
let odds = evens.map(v => v + 1);
let nums = evens.map((v, i) => v + i);
let pairs = evens.map(v => ({even: v, odd: v + 1}));
// Statement bodies
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v);
});
// Lexical this
let bob = {
_name: "Bob",
_friends: [],
printFriends() {
this._friends.forEach(f =>
console.log(this._name + " knows " + f));
}
}
http://facebook.github.io/react/
http://facebook.github.io/react/
https://facebook.github.io/react/docs/component-specs.html
https://facebook.github.io/react/jsx-compiler.html
https://facebook.github.io/react/docs/glossary.html
https://facebook.github.io/flux/
http://facebook.github.io/react/
Flux dans focus
Domains
Une application focus est composée de plusieurs dossiers.
Assets contient l'ensemble des ressources statiques de l'application:
Contient toute la configuration relative à l'application.
A priori il n'y a pas de raison de toucher régulièrement à ce dossier
( à part lorsque vous ajoutez un nouveau web service. )
Contient l'ensemble des traductions de l'application.
//Traductions
module.exports = {
contactInformations: {
firstName: 'Prénom',
lastName: 'Nom',
contacts: 'Nb de contact: __nb__'
}
}
//Clef associée
contactInformations.firstName
//Pour traduire
i18n.t('key', {options})
//ou
this.i18n('key) //Dans un composant
L'application dispose de différents initializers:
Domaines :
Focus.definition.domain.container.setAll(require('../config/domain'));Définitions des entités
Focus.definition.entity.container.setEntityConfiguration(require('../config/entity-definition'));Layout de l'application
let render = Focus.application.render;
let Layout = Focus.components.application.layout.component;
let MenuLeft = require('../views/menu');
render(Layout, 'body', {
props: {MenuLeft}
});
Contiendra l'ensemble des composants spécifiques au projet.
Par exemple un composant graphique pour effectuer une notation ou un montant de facture.
Le composant exporté doit être défini de la même manière que dans focus-components de manière à pourvoir être intégré à ce dernier.
Contient l'ensemble des routeurs de l'application.
module.exports = Focus.router.extend(
routes:{
'contact/:id(/:node)': 'contactRouteHandler'
},
contactRouteHandler(id, node){
let ContactView = require('views/contact');
//Rendu de la vue avec les paramètres dans le contenu de la page.
this._pageContent(ContactView, {props: {id: id}});
}
);
Ce sont des singletons, responsables des données de l'application.
Ils réagissent aux données transitant au sein du dispatcher via les actions. Ils notifient les composants en écoute des changements sur eux même.
let {CoreStore} = Focus.store;
module.exports = new CoreStore({
defintition: {
node1: 'node1',
node2; 'node2',
//Un noeud peut être n'importe quoi. Un object , une map, un tableau, ...
//Un noeud est l'unité minimale de donnée pour lequel un évènement de type 'modification' peut être lancé.
}
});Les actions sont déclanchées par un composant (loading, ...) ou par une action utilisateur (click sur un bouton, ...)
Elles ont pour but de faire transiter des données au sein du dispatcher en vue d'être traitée par les stores.
//Action 'brute"
function myAction(crit){
myService(crit).then((data)=>{
Focus.dispatcher.handleViewAction(
data: {
node: data
},
type: 'update'
});
});
}
//Action utilisant action-builder
//Retourne une fonction
module.exports = actionBuilder({
service: myService,
node: 'movie',
status: 'loaded'
});
//Fonctionne pour le cas très fréquent des blocs en chargement / édition.Les services sont responsables du chargement des données. Dans 90% des cas il s'agit d'appeler un web-service, il peut également s'agir d'appeler une base de donnée locale au navigateur. Par essence un service est asynchrone et retourne une Promise.
//L'url est lue depuis la configuration.
let URL = require('../../config/server');
//permet d'appeller un webservice en spécifiant une url, un verbe en spécifiant des données
// soit en paramètre soit en données postée.
//Réalise une xmlHttpRequest
let fetch = Focus.network.fetch;
module.exports = {
getMovieById(id) {
return fetch(URL.movie.get({urlData: {id: id}}))
}
}Les vues vont représenter les pages de l'application.
On peut en réaliser de plusieurs type:
// Mixins
let formMixin = Focus.components.common.form.mixin;
// Stores
let movieStore = require('stores/movie');
// Actions
let movieActions = require('action/movie').movie;
// Components
let Block = Focus.components.common.block.component;
module.exports = React.createClass({
definitionPath: 'movie',
displayName: 'MovieInformations',
mixins: [formMixin],
stores: [{store: movieStore, properties: ['informations']}],
action: movieActions,
renderContent: function renderMovieView() {
return (
<Block title='movie.detail.identity.title' actions={this._renderActions}>
{this.fieldFor('title')}
{this.fieldFor('released')}
{this.fieldFor('runtime')}
{this.fieldFor('countryIds')}
{this.fieldFor('languageIds')}
{this.fieldFor('genreIds')}
</Block>
);
}
});Créer une page qui affiche ce qu'est un contact.
# Ouvrir gitbash
# Se rendre dans el dossier où vous souhaitez récupérer les exercices
git clone https://github.com/pierr/focus-formation.git
cd focus-formation
npm install
npm run serveproblème de proxy: ça se passe ici
Parcours de la structure
Prenez le temps de regarder la structure de l'application.
Comme décrit au paragraphe précédent.
initialize.js, les initializers.