Directiva de edición en línea con AngularJS

Al hilo del proyecto de la aplicación para el control de competiciones de bolo palma, me he visto en la necesidad de que las distintas entidades, ya creadas, sean editables en línea por el usuario. Es decir, cada uno de los registros de la base de datos se muestran al usuario final en forma de tabla. A cada fila de la tabla se le añade un botón que transforma en editables los registros mostrados.

La primera aproximación fue la siguiente:

<tr ng-repeat="row in temporadas track by row.id">
  <td>
   <input type="text" class="form-control" ng-model="row.nombre" ng-if="editando[row.id]"/>
   <span ng-if="!editando[row.id]">{{row.nombre}}</span>
  </td>
  <td ng-click="EditarTemporada(row.id)"><span ng-if="!editando[row.id]" class="glyphicon glyphicon-edit"></span></td>
  <td ng-click="ActualizarTemporada(row)"><span ng-if="editando[row.id]" class="glyphicon glyphicon-ok"></span></td>
  <td ng-click="editando[row.id]=false"><span ng-if="editando[row.id]" class="glyphicon glyphicon-remove"></span></td>
  <td ng-click="BorrarTemporada(row.id)"><span class="glyphicon glyphicon-trash"></span></td>
</tr>

En función del valor de «editando[row.id]», que cambia al pulsar el botón de editar temporada, se muestra un campo de tipo input si es true o el valor del registro si es false. Al pulsar en el botón de guardar, se envía automáticamente al servidor para actualizar y, una vez actualizado se recarga la lista para mostrar los valores nuevos.

Si le damos una vuelta de tuerca, lo podemos transformar en una directiva de AngularJS, que nos permita reutilizar el código para las distintas entidades de las que consta la aplicación. A primera vista puede parecer sencillo, pero después de volverme un poco loco, me dí cuenta de que si le pasaba a la directiva la propiedad nombre del objeto row, cuando la editaba, el valor no se modificaba fuera del ámbito de la directiva. Y todo porque si utilizaba row.nombre, lo que se le pasa a la directiva es una referencia de la propiedad y no la propiedad en si, por lo que, a pesar del binding en ambos sentidos que proporciona Angular JS si se lo indicamos así en la definición de la directiva, el valor de row.nombre en el controlador principal no se veía alterado. Así que la solución fue pasarle a la directiva el objeto row completo e indicarle la propiedad del mismo que queremos editar.

Tras todo este rollo la directiva quedaría definida de la siguiente manera:

angular.module('sbAdminApp')
  .directive('editable', ()=> {
    return {
      restrict: 'E',
      replace: true,
      scope: {
        editando: '=',
        valor: '=',
        propiedad: '@'
      },
      template: '<span><input type="text" class="form-control" ng-model="valor[propiedad]" ng-if="editando"/>' +
        '<span ng-if="!editando">{{valor[propiedad]}}</span></span>'
    }
  });

Como vemos le asignamos un scope propio a la directiva, indicando que el «binding» debe ser en dos direcciones mediante el signo «=» o en una sola mediante «@». En «valor» le pasamos a la directiva el registro a editar completo. En «propiedad» le indicamos la propiedad del objeto que deseamos modificar y «editando» es un booleano que permite a la directiva mostrar el campo de texto o el de tipo input. Su uso en nuestra vista sería de la siguiente manera:

<tr ng-repeat="row in temporadas track by row.id">
   <td><editable propiedad="nombre" valor="row" editando="editando[row.id]"></editable></td>
   <td><editable propiedad="descripcion" valor="row" editando="editando[row.id]"></editable></td>
   <td ng-click="EditarTemporada(row.id)"><span ng-if="!editando[row.id]" class="glyphicon glyphicon-edit"></span></td>
   <td ng-click="ActualizarTemporada(row)"><span ng-if="editando[row.id]" class="glyphicon glyphicon-ok"></span></td>
   <td ng-click="editando[row.id]=false"><span ng-if="editando[row.id]" class="glyphicon glyphicon-remove"></span></td>
   <td ng-click="BorrarTemporada(row.id)"><span class="glyphicon glyphicon-trash"></span></td>
</tr>

Y el funcionamiento os lo dejo en las siguientes capturas:

[fusion_fusionslider name=»edicion_linea_angular_js» hide_on_mobile=»small-visibility,medium-visibility,large-visibility» class=»» id=»»][/fusion_fusionslider]

 

Rate this post

Pedro Pablo Moral

Licenciado en ADE. Experto Universitario en Gestión de RRHH por competencias-

Esta entrada tiene 2 comentarios

  1. i

    hola Pablo, me he lanzado a desarrollar una aplicación con JS completamente. Pero estoy bastante eprdido. Quería desarrollar la parte de registr/login y cierre de sesión de usuarios y no se muy bien cçomo ponerlo en marcha…

    me recomiendas utilizar angular?

    1. pedropablomoral

      Hola i, gracias por tu comentario. Si que te recomiendo el uso de angular para la parte del frontend. Tengo hecho algo parecido de login para Android, pero te puede servir de inspiración.
      Login android

Deja una respuesta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.