Bonjour

Webix est un librairie qui fournie clef en main un très grand nombre de widgets.
(Je n'ai à ce jour jamais eu besoin d'en chercher ailleurs, I.E. j'ai toujours trouvé mon bonheur dans la lib)

Contrairement à l'approche d'Angular JQuery etc Webix part du principe que c'est le code qui défini l'IHM. il n'est ici pas question d'écrire du html du css du js et d'avoir un processus de binding. on écrit du js et que du js.

Je trouve cette librairie plutôt bien adapté lorsqu'on fait des choses très industrielle afficher des grilles des graphes éditer un élément etc. C'est à mon avis beaucoup moins adapté lorsqu'on veut une personnalisation (pour l'entreprise) très poussée.

Avec Webix vient webix-jet qui est un micro framework pour les single page applications.

J'ai une application écrite il y a deux ans qui entre dans ce cadre il y a des dizaines de modules qui on tous le même aspect en gros afficher une grille de donnée ou des graphes pour surveiller des indicateurs.
pour se faire rien de plus simple
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
	var bundlesDatatable = {
		view : "customDatatable",
		id : "bundles:datatable",
		select : "row",
		navigation : true,
		resizeColumn : true,
		url : bundlesStateUrl,
		ready : function() {
			this.markSorting("SymbolicName", "asc");
			this.sort("SymbolicName", "asc", "string");
		},
		columns : [ {
			id : "check",
			header : {
				content : "masterCheckbox"
			},
			template : "{common.checkbox()}",
			width : 40
		}, {
			id : "flux",
			header : [ "Interface", {
				content : "customSelectFilter"
			} ],
			sort : "string",
			adjust : true
		}, {
			id : "recipientName",
			map : "#recipient.name#",
			header : [ "Socle", {
				content : "customSelectFilter"
			} ],
			sort : "string",
			adjust : true
		}, {
			id : "SymbolicName",
			header : [ "Module", {
				content : "customTextFilter"
			} ],
			sort : "string",
			adjust : true
		}, {
			id : "State",
			header : [ "Etat", {
				content : "customSelectFilter"
			} ],
			sort : "string",
			adjust : true,
			cssFormat : function(value) {
				if (value.toLowerCase() == "active") {
					return {
						color : "green"
					};
				} else if (value.toLowerCase() == "installed" || value.toLowerCase() == "resolved") {
					return {
						color : "black"
					};
				} else if (value.toLowerCase().includes("fail")) {
					return {
						color : "red"
					};
				}
			}
		}, {
			id : "HermesRoute",
			header : [ "Routes", {
				content : "selectFilter",
				compare : function match(a, b) {
					return a.toString() == b;
				}
			} ],
			sort : "string",
			adjust : true
		}, {
			id : "Version",
			header : [ "Version", {
				content : "customTextFilter"
			} ],
			sort : "string",
			adjust : true
		}, {
			id : "description",
			header : [ "Description", {
				content : "customTextFilter"
			} ],
			sort : "string",
			adjust : true
		}]
	};
et voilà une grille de donnée qui s'affiche et qui charge ces données via ajax (bundlesStateUrl)
Il n'y a pas plus de code pour afficher une grille et charger son contenu
un bouton bundlesDatatable.load() et on recharge les données

pour rafraîchir les données régulièrement un timer appelle de façon cyclique le serveur pour avoir les dernière data.

Cela à un gros inconvénient. On invoque le serveur lorsque il n'y a pas de nouvelles data et on ne l'invoque pas lorsqu'il y en a
soit on fait un cycle rapide pour avoir toujours les dernières mais de très nombreuse fois il n'y a rien de neuf et on le fait pour rien
soit on fait un cycle lent et s'il y a du changement on ne le sait que trop tard.

Depuis que cette application a été écrite les websocket sont devenu une techno mature. les dernières version de webix sont capable de l'utiliser.
l'exemple le plus courant est le chat. un chat est une liste de message du coup webix s'est basé sur cometd faye pour dialoguer avec un seveur cometd.
cometd propose un protocole beaucoup plus complexe que websocket.
il s'agit d'un protocole publication abonnement. le client initie le dialogue et en fonction des capacité du client et du serveur une forme de dialogue va être trouvé parmis lesquels le websocket.

cela implique d'embarquer dans sont serveur tous ce système de dialogue ce qui n'est pas nécessairement ce qu'on veut ou peut. deplus les information que pousse le serveur vers le client sur un canal sont de la forme ajouter A, supprimer B, Modifier C etc.

là encore ce n'est pas nécessairement ce qui correspond au besoin.

Revenons à mon cas une grille contient un ensemble de lignes avec des valeurs d'indicateurs. l'ensemble des lignes (petit nombres) entre dans la page
à chaque nouvel état la majorité sinon la totalité des valeurs ont changées beaucoup de ligne supprimées et beaucoup de lignes ajoutées.
en clair il est beaucoup plus simple et efficace de recevoir toutes les données à chaque fois. si je suis caricatural j'ai 100 lignes j'en supprime 50 ajoute 50 et modifie 49
avec un système comme faye j'ai 50 ordre de suppression 50 ordre d'ajout et 49 de modification soit 149 ordres si je reçois tout j'ai 100 lignes.

pour les graphes deux cas à chaque itération sur 30 valeur j'en supprime 1 et en ajoute 1 ou à chaque itération l'ensemble des valeurs à changé dans les deux cas les séries (nom des indicateurs) sont fixe. pour le premier cas faye est bien à chaque itération je reçois une suppression et un ajout par indicateur. pour le second l'envoi de la totalité des données est préférable.


Ce qu'il se cache derrière l'attribut url de la datatable est en fait bien plus compliqué
implicitement une dataColection est crée et associé à la table à cette data collection est aussi associé un proxy de lecture/écriture des données
avec une simple url il s'agit par défaut d'ajax en json. mais on peut utiliser bien d'autre format et aussi choisir son protocole. il y a un proxy indexdb pour écrire dans la base indexdb du browser, localstorage, rest, faye, etc.

toute vue associé à la dataCollection est mise à jour automatiquement lorsqu'une données est changée. tout composant qui modifie une donnée empêche toute modification le temps de l’opération. en clair c'est magique on s'occupe de rien.

la forme des url est classique si on veut utiliser un proxy la syntaxe est simple
Code : Sélectionner tout - Visualiser dans une fenêtre à part
url : "rest->/data/mouthresults"
La mise à jour des données via websocket a donc consisté à créer un nouveau type de proxy
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//proxy.js file
//define au new proxy for websoket
 
(function() {
	var webSocketProxy = {
		$proxy : true,
		load : function(collection, callback, params) {
			// just register the collection to be updated
			this.collections.push(collection);
		},
		// create the websoket to be connected
		init : function() {
			this.collections = [];
 
			if (!window.WebSocket) {
				webix.message({
					text : 'WebSocket not supported by this browser',
					type : 'error',
					expire : -1
				});
			} else {
				// internal websocket object
				var server = {
					connect : function() {
						var location;
						if (this.source.startsWith("//")) {
							location = 'ws:' + this.source;
						} else {
							location = 'ws://' + window.location.host
									+ this.source;
						}
						webix.message({
							text : location,
							type : 'debug'
						});
						this.ws = new WebSocket(location);
								this.ws.collections = this.collections,
								this.ws.source = this.source,
 
								// send a message to server after open socket
								this.ws.onopen = function() {
									this.send({
										text : 'websockets are open for communications!'
									});
								};
 
						// on recive message
						this.ws.onmessage = function(m) {
							if (m.data) {
								// webix.message(m.data);
 
								var json = webix.DataDriver.json.toObject(
										m.data, false)
								// console.log(json);
								for (var i = 0; i < this.collections.length; i++) {
									if (this.collections[i].data) {
										this.collections[i].data._parse(json);
									}
								}
							}
						};
 
						// alert when server close connection
						this.ws.onclose = function(m) {
							webix.message({
								text : 'ws closed',
								type : 'error',
								expire : -1
							});
							server.ws = null;
						};
					},
 
					init : function(collections, source) {
						this.collections = collections;
						this.source = source;
					},
 
					send : function(text) {
						if (text != null && text.length > 0)
							if (this.ws)
								this.ws.send(message);
					}
				};
				server.init(this.collections, this.source);
				server.connect();
			}
 
		}
	};
 
	// register the proxy in webix
	webix.proxy.ws = webSocketProxy;
})();
l'url de ma vue est devenue

Code : Sélectionner tout - Visualiser dans une fenêtre à part
url : "ws->/data/mouthresults"
et c'est tout.
lorsque la vue est crée la dataCollection l'est aussi "ws->" déclencha la création du proxy et son initialisation
le web socket est créé.
lorsque la dataCollection est initialisée elle appelle la méthode load. le proxy enregistre la collection comme devant être mise à jour.

à chaque message reçu du serveur on récupère le json et on le met dans la collection.
toutes les vues sont mise à jour.

pour vous donner une idée du résultat (ce n'est pas mon code pas de web socket sur snippet)
https://snippet.webix.com/jetmenu
vous avez là une micro exemple (notez qu'en 50 ligne vous avez une appli évidemmentsimple)


à la ligne 13 enlevez autoconfig ajouté la définition des colonnes et l'url url : "ws->/data/mouthresults".
enlevez les 15 16 17 et la grille lorsque vous cliquez sur data est mise à jour en temps réel

A+JYT