Foros del Web » Programando para Internet » Javascript » Frameworks JS »

AngularJS y adios a los input (CONTENTEDITABLE)

Estas en el tema de AngularJS y adios a los input (CONTENTEDITABLE) en el foro de Frameworks JS en Foros del Web. Hey que tal, amigos de foros del web, soy nuevo en el foro, hace varios días estuve pensando en unirme a la comunidad que tanto ...
  #1 (permalink)  
Antiguo 18/10/2015, 06:17
 
Fecha de Ingreso: octubre-2015
Mensajes: 18
Antigüedad: 8 años, 6 meses
Puntos: 1
Información AngularJS y adios a los input (CONTENTEDITABLE)

Hey que tal, amigos de foros del web, soy nuevo en el foro, hace varios días estuve pensando en unirme a la comunidad que tanto me ha ayudado, desde hace ya tiempo, y regresar el conocimiento que he adquirido gracias a ustedes.

Escogí un tema algo complejo, pero a la vez fascinante, hablando de una posible evolución de como nos comunicamos del cliente al servidor, gracias a la bendita tecnología de AngularJS y las novedades de HTML 5, las formas en que diseñamos e interactuamos con el usuario es mucho mas dinámica, así que sin mas preámbulo comencemos...


Angular y el adios a los input (CONTENTEDITABLE)

Con la llegada de la nueva tecnologia de HTML 5, la forma en la que una persona se relaciona con el sitio es ahora mas dinamica, visual y divertida. Pero aun asi HTML necesita ayuda para las complejas tareas que queramos hacer con el, para eso llego nuestro fabuloso Angular, que de alguna manera a cambiado la forma en que se construyen las paginas HTML.

Durante mucho tiempo la única manera de que el usuario ingresara datos consiente mente, era gracias nuestros input, ya sea de tipo text, file, number etc.., pero sobre todo con la creciente necesidad de hacer web's mas amigables con el usuario, llega una función (atributo) para los elementos contenedores (Div, span, p...) puedan ser editados por los mismos usuarios. Bajo esa idea se concibió CONTENTEDITABLE un atributo que puede convertir un simple div estático y aburrido, en algo fascinante y maravilloso.

Una de estas bendiciones ha sido el atributo CONTENTEDITABLE, quiero hacer énfasis en que no estoy proponiendo en que las etiquetas con dicho atributo sean una mejor opción que los input (aunque con el tiempo pueda llegar a serlo),
el atributo no fue diseñado para remplazar dichas etiquetas, estas etiquetas no pueden formar un comportamiento con dichos input, ya que no existe un atributo action, method o cualquiera que remplaze a uno de este tipo, pero gracias a Angular (y Javascript en crudo) es posible que estos elementos se comporten de una manera mucho mas eficiente y SEXY en nuestro sitio.

Sin mas palabras, manos a la obra!

Como ya les he mencionado los CONTENTEDITABLE no son naturalmente dinámicos, hay que inyectarles vida con javascript, si puedes observar al definir un elemento con el ya mencionado atributo, no obtendrás, mas que un div vació (si esta vació), pero con una diferencia, cuando haces clic en el podrás observar que el navegador pone el foco en el (la barrita que parpadea) y se comporta como un input, pero con la diferencia de que este crece tanto horizontal, como vertical acoplándose al texto y el espacio disponible. (Una alternativa excelente para responsive design).

He aquí, como se define un elemento con CONTENTEDITABLE:

Código HTML:
<div contenteditable="true">Hola yo soy un div, en el que puedes borrar este texto</div>

<p contenteditable="true">Yo también puedo ser editado</p>

<span contenteditable="true">Yo también</span> 
Como puedes ver, el atributo se indica y recibe un true o false, obviamente para desactivar o activar la editabilidad, pero se puede ser muy versatil con esta etiqueta, pero no abuses como en el siguiente ejemplo:

Código HTML:
<div contenteditable="true">Hola yo soy un div, en el que puedes borrar este texto.

<div contenteditable="false">Yo no puedo ser editado, sin embargo puedo ser eliminado</div>

</div> 
Para mas información de este increíble atributo puedes visitar:

[URL="http://web.ontuts.com/tutoriales/contenteditable-contenido-editable-en-html5/"] Ontuts [/URL]

Bien ahora, a la parte interesante, ¿como puedo convertir esto en un input?, facil con javascript, mejor dicho con Angular, y vamos a ver como obtener el contenido de un div y como convertirlo en elemento de doble-binding.

He aqui el codigo para extraer el codigo:

Código HTML:
<div contenteditable="true"> Hola mundo! </div>

<script>

//Previamente debes cargar angular, Claro!

var element = angular.element(document.querySelector(".miclase"));

var content = element.html();

</script> 
Asi de facil y sencillo, pero esto no tiene doble-binding, y para ser sincero es un problema que el equipo de angular no haya hecho algo con este problema,
como puedes ver, un contenteditable no puede tener doble binding, pero el mismo equipo de angular y el usuario de github akatov nos dan la solucion:

Código HTML:
<body ng-app="myapp" ng-controller="general">

<div contenteditable="true" ng-model="texto"> Hola mundo! </div>

<p>{{texto}}</p>

<script>

//Previamente debes cargar angular, Claro!

var app = angular.module('myapp', []);

app.directive('contenteditable', ['$timeout', function($timeout) { 
    return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
      // don't do anything unless this is actually bound to a model
      if (!ngModel) {
        return
      }

      // options
      var opts = {}
      angular.forEach([
        'stripBr',
        'noLineBreaks',
        'selectNonEditable',
        'moveCaretToEndOnChange',
        'stripTags'
      ], function(opt) {
        var o = attrs[opt]
        opts[opt] = o && o !== 'false'
      })

      // view -> model
      element.bind('input', function(e) {
        scope.$apply(function() {
          var html, html2, rerender
          html = element.html()
          rerender = false
          if (opts.stripBr) {
            html = html.replace(/<br>$/, '')
          }
          if (opts.noLineBreaks) {
            html2 = html.replace(/<div>/g, '').replace(/<br>/g, '').replace(/<\/div>/g, '')
            if (html2 !== html) {
              rerender = true
              html = html2
            }
          }
          if (opts.stripTags) {
            rerender = true
            html = html.replace(/<\S[^><]*>/g, '')
          }
          ngModel.$setViewValue(html)
          if (rerender) {
            ngModel.$render()
          }
          if (html === '') {
            // the cursor disappears if the contents is empty
            // so we need to refocus
            $timeout(function(){
              element[0].blur()
              element[0].focus()
            })
          }
        })
      })

      // model -> view
      var oldRender = ngModel.$render
      ngModel.$render = function() {
        var el, el2, range, sel
        if (!!oldRender) {
          oldRender()
        }
        var html = ngModel.$viewValue || ''
        if (opts.stripTags) {
          html = html.replace(/<\S[^><]*>/g, '')
        }

        element.html(html)
        if (opts.moveCaretToEndOnChange) {
          el = element[0]
          range = document.createRange()
          sel = window.getSelection()
          if (el.childNodes.length > 0) {
            el2 = el.childNodes[el.childNodes.length - 1]
            range.setStartAfter(el2)
          } else {
            range.setStartAfter(el)
          }
          range.collapse(true)
          sel.removeAllRanges()
          sel.addRange(range)
        }
      }
      if (opts.selectNonEditable) {
        element.bind('click', function(e) {
          var range, sel, target
          target = e.toElement
          if (target !== this && angular.element(target).attr('contenteditable') === 'false') {
            range = document.createRange()
            sel = window.getSelection()
            range.setStartBefore(target)
            range.setEndAfter(target)
            sel.removeAllRanges()
            sel.addRange(range)
          }
        })
      }
    }
  }}]);

app.controller('general', ['$scope', function($scope) {
    $scope.texto="<i>" + s.texto + "</i>"
  }])  

</script>

</body> 
Les explico, el elemento con la directiva contenteditable, relaciona el contenido del div con el $scope por medio de link y ngModel, al mismo teimpo que actualiza la vista con el contenido del modelo, eso es doble binding, y como puedes ver el ejemplo [URL="http://akatov.com/angular-contenteditable/examples/simple.html"]aquí.[/URL]

Bueno les agradezco mucho todo lo que me han enseñado y no olviden darle gracias a Angular.

Gracias!

Thank you very much Akatov!!!

Etiquetas: angular, bind, content, double, html, javascript
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 18:23.