Partage
  • Partager sur Facebook
  • Partager sur Twitter

todolist avec socket.io et angular.js

voici ce que j'ai envoyé a la derniere minute

    6 août 2014 à 0:09:57

    voila je viens de finir mon exo du cours sur le node.js

    voici les pages de codes que j'ai envoyé:

    css : view-source:http://www.grafikart.fr/demo/JS/AngularTodo/css/base.css il n'a pas changé d'un iota... mise à part le nom

    html :

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
            <title></title>
            <link rel="stylesheet" href="style.css">
            <!--[if lt IE 9]>
              <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
            <![endif]-->
    
        </head>
        <body ng-app="todo">
    
          <section id="todoapp" ng-controller="TodoCtrl">
            <header id="header">
              <h1>TodoList</h1>
              <form id="todo-form" ng-submit="addTodo()">
                <input type="text" id="new-todo" placeholder="Ajouter une Nouvelle tâche" autofocus autocomplete="off" ng-model="newtodo">
              </form>
            </header>
    
            <section id="main">
              <input type="checkbox" id="toggle-all" ng-model="allchecked" ng-click="checkAllTodo(allchecked)">
              <ul id="todo-list">
                <li ng-repeat="todo in todos | filter:statusFilter" ng-class="{completed : todo.completed, editing: todo.editing}" ng-dblclick="todo.editing = true">
                  <div class="view">
                    <input type="checkbox" class="toggle" ng-model="todo.completed">
                    <label>{{todo.name}}</label>
                    <button class="destroy" ng-click="removeTodo($index)"></button>
                  </div>
                  <form action="#">
                    <input class="edit" ng-model="todo.name" ng-blur="editTodo(todo)">
                  </form>
                </li>
              </ul>
            </section>
    
            <footer id="footer">
              <span id="todo-count"><strong>{{remaining}}</strong> Tâches restantes</span>
              <ul id="filters">
                <li><a href="#/" ng-class="{selected: location.path() == '/'}">Toutes</a></li>
                <li><a href="#/active" ng-class="{selected: location.path() == '/active'}">Active</a></li>
                <li><a href="#/done" ng-class="{selected: location.path() == '/done'}">Finit</a></li>
              </ul>
            </footer>
    
          </section>
    
          <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
          <script type="text/javascript" src="app.js"></script>
    	  <script src="/socket.io/socket.io.js"></script>
        </body>
    </html>
    

    app.js

    var app = angular.module('todo', []);
    
    
    app.directive('ngBlur', function(){
    	return function(scope, elem, attrs){
    		elem.bind('blur', function(){
    			scope.$apply(attrs.ngBlur);
    		})
    	}
    })
    
    
    
    app.controller('TodoCtrl', function($scope, filterFilter, $http, $location){
    	$scope.todos = [];
    	
    				var host = location.origin;
    				var socket = io.connect(host);
    
    				// mise a jour du cache sur le nouveau client :-/
    				socket.on('cache', function(cache){
    		  			$scope.todos.push(cache);
    		  			$scope.$apply();
    		  		});
    				
    				// mise a jour des ajouts
    				socket.on('name', function(name){
    		  			$scope.todos.push({name : name, completed : false});
    		  			$scope.$apply();
    		  		});
    	
    				// mise a jour des suppressions
    				socket.on('clear', function(idx){
    		  			$scope.todos.splice(idx,1);
    		  			$scope.$apply();
    		  		});
    
    	// actions filtres
    	$scope.$watch('todos', function(){
    		$scope.remaining = filterFilter($scope.todos, {completed:false}).length;
    		$scope.allchecked = !$scope.remaining;
    	}, true)
    
    	// tache fini ou non
    	if($location.path() == ''){ $location.path('/')}
    	$scope.location = $location;
    	$scope.$watch('location.path()', function(path){
    		$scope.statusFilter =
    			(path == '/active') ? {completed : false} :
    			(path == '/done') ? {completed : true} :
    			null;
    	});
    
    	// ordre de suppression
    	$scope.removeTodo = function(index){
    		socket.emit('clear',index)
    	}
    	// ajout tache
    	$scope.addTodo = function(){
    		
    			name = $scope.newtodo;
    		socket.emit('name',name)
    		$scope.newtodo = '';
    		return false;
    	}
    	// rééditer tache
    	$scope.editTodo = function(todo){
    		todo.editing = false;
    	}
    	// sélectionner toutes les taches
    	$scope.checkAllTodo = function(allchecked){
    		$scope.todos.forEach(function(todo){
    			todo.completed = allchecked;
    		})
    	}
    
    });
    

    serveur.js

    var express = require('express')
      , app = express()
      , server = require('http').createServer(app)
      , io = require('socket.io').listen(server);
    
    app.use(express.static(__dirname + '/'));
    
    
    
    server.listen(8080);
    
    var i = 0,cache, name ='',index = '', todos =[],newId =[];
    
    io.sockets.on('connection', function (socket) {
    		
    		// aurait du envoyer le cache sur le nouveau client :-/
    		newId.push(socket.id)
    		if ( newId.length == 1){
    		newId.splice(0,1);
    		i = todos.length
    		for (var j = 0; j < i; j++){
    			cache = todos[j]
    				io.sockets.socket(socket.id).emit('cache', cache);
    		}
    		}
    		else {
    			console.log(todos)
    		}
    
      socket.emit('name', name);
      socket.on('name', function(name){
    	todos.push({name : name, completed : false});
    	
    	 console.log(todos)
    
      	io.sockets.emit('name', name);
      })
    
      socket.emit('clear', index);
      socket.on('clear', function(idx){
    	todos.splice(index,1);
    	console.log(todos)
      	io.sockets.emit('clear', index);
      })
      
    });
    

    json :

    {
      "name": "TPtodolistOC ",
      "version": "0.0.1",
      "private": true,
      "dependencies": {
        "express": "3.x",
        "socket.io": "0.9.14"
      }
    }

    je me suis basé pas mal sur ce tuto que j'ai déjà suivi pas à pas puis pour le socket io je suis parti sur ce tuto la (pour dire que je suis parti de tres loin pour tout ce qui est insertion des instructions socket.io dans la todolist originale).

    ce qui marche sur ce code (testé simultanément sur 2 navigateur différent):

    • mise a jours des nouvelles taches
    • suppression des taches
    • "l'historique" des taches existant ( le client qui vient de se connecter récupere la liste.... j'ai eu du mal:p).

    ce qui ne marche pas :

    • les taches exécuté peuvent être cochées
    • les taches exécuté peuvent tous être cochées en une fois
    • (ah oui j'oubliais) la réédition des taches ....
    • et un bug d'affichage sur la fin de la todolist quand on charge la page.... je sais pas pourquoi...

    Ce que je souhaite c'est qu'on m'aide à "finir" une 2eme fois ce code sur ces 4 dernier points et une "simplification" des codes app & serveur... "à tête reposé";) si ca interesse quelqu'un ...

    ______

     "un bug d'affichage sur la fin de la todolist quand on charge la page.... je sais pas pourquoi..."

    en fait je me suis appérçu que mon code quelque part me "bouffe" la première tache et me rajoute une "tache vide" ...o_O

    -
    Edité par Manuel CQE 6 août 2014 à 8:30:55

    • Partager sur Facebook
    • Partager sur Twitter

    L’éternel débutant...

      6 août 2014 à 9:02:17

      Hello,

      Alors, j'ai pas un niveau pharaonique en AngularJS, mais je vois 2/3 trucs qui me perturbent :)

      1) Quand je clique sur l'action DELETE (la croix à droite) ça me vire... toujours la 1ère tâche de la liste, pas nécessairement celle appartenant à la ligne où j'ai cliqué.

      Pourquoi ?

        socket.on('clear', function(idx){
          todos.splice(index,1);
          console.log(todos)
          io.sockets.emit('clear', index);
        })

      Perso, je l'ai corrigé de mon côté, à toi de trouver l'erreur dans ce bout de code ;)

      2) Le coup du "bug" d'affichage à la fin de la todolist, ça provient de quand tu démarres ton AngularJS.

      Pour faire simple, HTML charge la page et, à la fin, va chercher le JS pour Angular (la référence mise en bas de page par souci d'optimisation de code).

      Bon, alors oui, c'est bien de mettre le JS en bas de page, ça permet un rendu plus rapide, mais parfois... ça pose problème :)

      Dans le cadre d'un exercice de cours, tu peux remonter ton AngularJS en tête de page (ça se défend, c'est ton moteur de rendu après tout) ou jouer sur les displays pour cacher les éléments "Angularisés" (paye ton néologisme foireux) et ensuite switch le display une fois AngularJS chargé.

      Pour les 3 autres points qui ne fonctionnent pas... je n'ai pas compris :p

      Une fois cochée, on ne doit pas pouvoir recocher la tâche c'est ça ?

      Si oui, tu as 2 choses à faire => dans AngularJS, abort l'action de "coche" si la tâche est déjà cochée, et dans ton server.js, ... et bien, la même chose :) au cas où un petit malin modifie le JS côté client, au moins ton JS côté serveur saura quoi faire.

      Idem pour les autres, tu dois palier à ce souci côté Angular et côté Node :)

      J'essaye d'être évasif pour pointer dans la bonne direction et ne pas te donner les réponses toutes crues :p

      Bonne chance !

      [Edit]

      Par contre, fait TRES attention au point-virgule à la fin de tes commandes JS... utilises un Linter qui va contrôler ton code JS et te dire "tu as oublié ça là" pour bien faire.

      Au choix, JSHint (un peu trop "strict" mais très bien) ou JSLint (un tout petit peu moins strict et très bien).

      Si tu utilises node, avec une commande npm install -g jshint, une fois installé : "jshint server.js" te listera tes "erreurs" (server.js si ton JS s'appelle comme ça, et en te positionnant dans le répertoire ;) )

      -
      Edité par Airin 6 août 2014 à 9:30:14

      • Partager sur Facebook
      • Partager sur Twitter
      Apprendre peut être long et difficile, mais abandonner n'accélère certainement pas le processus.
        6 août 2014 à 12:04:39

        Airin a écrit:

         Quand je clique sur l'action DELETE (la croix à droite) ça me vire... toujours la 1ère tâche de la liste, pas nécessairement celle appartenant à la ligne où j'ai cliqué.

        tien bizarre jusqu'a ce que je l'envoie ca marchait .... :o, et depuis la correction des exercices ca marche plus comme il faut... (et le pire c'est qu'avant l'envoi et  il supprimait bien dans l'ordres ....o_O)

        pire : "info  - unhandled socket.io url " alors que je me suis connecté ...

        je suis bon pour  revoir tt mes modules

         ______

        après la réinstallation des dépendance je dois admettre que la suppression se faisait toujours sur la première ligne ....

        ______

        bon le 1) et 2) c'est réglé ...(changement de "idx" en index et positionnement des appels de scripts en amont de "body")

        Airin a écrit:

        Pour les 3 autres points qui ne fonctionnent pas... je n'ai pas compris :p

        Une fois cochée, on ne doit pas pouvoir recocher la tâche c'est ça ?

        Si oui, tu as 2 choses à faire => dans AngularJS, abort l'action de "coche" si la tâche est déjà cochée, et dans ton server.js, ... et bien, la même chose :) au cas où un petit malin modifie le JS côté client, au moins ton JS côté serveur saura quoi faire.

        en fait c'est la répercutions des cases à cocher qui m'importe (celles à coté des taches qui sert a cocher les taches unitairement, et celle qui est devant le champ qui sert a ajouter les tache qui coche toutes les taches)

        quant à l'édition la tache : quand tu clique sur la tache tu peux modifier la tache mais bon je crois que j'ai une idée derrière la tête pour ça... (quoi qu'en regardant le code de pres c'est pas si simple que ca :euh:)

        car tt se passe dans

        app.directive('ngBlur', function(){
            return function(scope, elem, attrs){
                elem.bind('blur', function(){
                    scope.$apply(attrs.ngBlur);
                })
            }
        })

        et

        // rééditer tache
            $scope.editTodo = function(todo){
                todo.editing = false;
            }

        code obscure dont je ne vois pas comment intégrer une instruction soket.io la dedans (parcontre en meme temps qu'on reçois les donnée pour la maj de "todos=[]" coté serveur on fais un splice de tel sorte qu'on change l'item )



        -
        Edité par Manuel CQE 6 août 2014 à 15:34:45

        • Partager sur Facebook
        • Partager sur Twitter

        L’éternel débutant...

          6 août 2014 à 16:48:39

          Re,

          La partie "app.directive" n'applique qu'un effet graphique sur tes éléments... je doute qu'il soit intéressant dans le cas présent :)

          Un indice pour gérer l'édition et l'effet "coché" ?

          <input type="checkbox" class="toggle" ng-model="todo.completed">

          Ici, tu updates une valeur de ton modèle MAIS tu ne passes pas par du JS pour lever un socket.emit('check') (exemple de nom) de fait, tu ne propages pas l'information vers le serveur.

          C'est valable pour l'édition également et ton checkAll :)

          Je peux me tromper et j'ai pu louper des choses dans la partie AngularJS, mais je pense que c'est une piste à creuser...

          Bon courage !

          • Partager sur Facebook
          • Partager sur Twitter
          Apprendre peut être long et difficile, mais abandonner n'accélère certainement pas le processus.
            10 août 2014 à 22:00:22

            Bon pour la transmission des checkbox c'est vraiment tiré par les cheveux mais j'ai trouvé! Et en fin de compte ce qui m'a mis la puce à l'oreille c'est :
                // sélectionner toutes les taches
                $scope.checkAllTodo = function(allchecked){
                    $scope.todos.forEach(function(todo){
                        todo.completed = allchecked;
                    })
                }
            et 
            <input type="checkbox" id="toggle-all" ng-model="allchecked" ng-click="checkAllTodo(allchecked)">


            donc j'ai complété :

            <input type="checkbox" class="toggle" ng-model="todo.completed">

             par

            <input type="checkbox" class="toggle" ng-model="todo.completed" ng-click="todoCompleted($index)">

            et pour finir on a coté serveur :

            var express = require('express')
              , app = express()
              , server = require('http').createServer(app)
              , io = require('socket.io').listen(server);
            
            app.use(express.static(__dirname + '/'));
            
            
            
            server.listen(8080);
            
            var i = 0,cache, name ='',index = '', todos =[],newId =[], x, allchecked, completed;
            
            io.sockets.on('connection', function (socket) {
            		
            		
            
            	  socket.emit('name', name);
            	  socket.on('name', function(name){
            		todos.push({name : name, completed : false});
            		
            		 console.log(todos);
            
            		io.sockets.emit('name', name);
            	  })
            
            	  socket.emit('clear', index);
            	  socket.on('clear', function(index){
            		todos.splice(index,1);
            		console.log(todos);
            		io.sockets.emit('clear', index);
            	  })
            	  
            	  socket.emit('completed', index);
            	  socket.on('completed', function(index,completed){
            		todo = todos[index];
            		todo.completed = completed;
            		console.log(todos[index]);
            		io.sockets.emit('completed',index,completed);
            	})	
            	  socket.emit('allchecked', allchecked);
            	  socket.on('allchecked', function(allchecked){
            		for (x in todos) {
            			todo = todos[x];
            			todo.completed = allchecked;
            		};
            		io.sockets.emit('allchecked',allchecked);
            	  })
            	  
            	  // allez donc savoir le fait d'avoir mis ce morceau a la fin a résolu le bug...
            			newId.push(socket.id)
            			if ( newId.length == 1){
            			newId.splice(0,1);
            				if (todos != undefined){
            					i = todos.length 
            					for (var j = 0; j < i; j++){
            						cache = todos[j]
            						console.log(cache);
            							io.sockets.socket(socket.id).emit('cache', cache);
            					}
            				}
            			}
            			else {
            				console.log(todos)
            			}
            	  
            });
            

            et coté app :

            var app = angular.module('todo', []);
            
            
            app.directive('ngBlur', function(){
            	return function(scope, elem, attrs){
            		elem.bind('blur', function(){
            			scope.$apply(attrs.ngBlur);
            		})
            	}
            })
            
            
            
            app.controller('TodoCtrl', function($scope, filterFilter, $http, $location){
            	$scope.todos = [];
            	
            				var host = location.origin;
            				var socket = io.connect(host);
            
            				// mise a jour du cache sur le nouveau client 
            				socket.on('cache', function(cache){
            		  			$scope.todos.push(cache);
            		  			$scope.$apply();
            		  		});
            				
            				// mise a jour des ajouts
            				socket.on('name', function(name){
            		  			$scope.todos.push({name : name, completed : false});
            		  			$scope.$apply();
            		  		});
            	
            				// mise a jour des suppressions
            				socket.on('clear', function(idx){
            		  			$scope.todos.splice(idx,1);
            		  			$scope.$apply();
            		  		});
            				
            				// mise a jour état de la tache
            				socket.on('completed', function(index,completed){
            					todo = $scope.todos[index];
            					todo.completed = completed
            					$scope.todos.splice(index,1,todo);
            		  			$scope.$apply();
            		  		});
            				
            				// mise a jour état de la tache allchecked
            				socket.on('allchecked', function(allchecked){
            					$scope.todos.forEach(function(todo){
            						todo.completed = allchecked;
            					})
            		  			$scope.$apply();
            		  		});
            
            	// actions filtres
            	$scope.$watch('todos', function(){
            		$scope.remaining = filterFilter($scope.todos, {completed:false}).length;
            		$scope.allchecked = !$scope.remaining;
            	}, true)
            
            	if($location.path() == ''){ $location.path('/')}
            	$scope.location = $location;
            	$scope.$watch('location.path()', function(path){
            		$scope.statusFilter =
            			(path == '/active') ? {completed : false} :
            			(path == '/done') ? {completed : true} :
            			null;
            	});
            
            	// ordre de suppression
            	$scope.removeTodo = function(index){
            		socket.emit('clear',index)
            	}
            	
            	// état de la tache 
            	$scope.todoCompleted = function(index){
            		test = $scope.todos[index]
            		completed = test.completed
            		socket.emit('completed',index,completed)
            	}
            	
            	// ajout tache
            	$scope.addTodo = function(){
            		
            			name = $scope.newtodo;
            		socket.emit('name',name)
            		$scope.newtodo = '';
            		return false;
            	}
            	// rééditer tache
            	$scope.editTodo = function(todo){
            		todo.editing = false;
            	}
            	// sélectionner toutes les taches
            	$scope.checkAllTodo = function(allchecked){
            		socket.emit('allchecked',allchecked)
            		$scope.todos.forEach(function(todo){
            			todo.completed = allchecked;
            		})
            	}
            
            
            	
            });
            
            

             ...oui c'est vraiment, vraiment, vraiment tiré par les cheveux... mais ça fonctionne!!! en tout cas... :p

            j'ai aussi profité de corriger le bug qu'il y avait lors de l'appel du cache du serveur :

            CQEadsurf a écrit:

             "un bug d'affichage sur la fin de la todolist quand on charge la page.... je sais pas pourquoi..."

            en fait je me suis appérçu que mon code quelque part me "bouffe" la première tache et me rajoute une "tache vide" ...o_O

            ______

            il ne me reste plus que l’éditeur de tache (ce qui permet de modifier les taches) et je pourrais mettre ce sujet comme résolu!!!:D

            -
            Edité par Manuel CQE 11 août 2014 à 11:55:17

            • Partager sur Facebook
            • Partager sur Twitter

            L’éternel débutant...

            todolist avec socket.io et angular.js

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown