Académique Documents
Professionnel Documents
Culture Documents
js
Utilice Knockout.js para diseñar y crear aplicaciones web dinámicas
del lado del cliente que son extremadamente sensibles y fáciles de " Este libro es un gran
mantener. Este ejemplo Libro muestra cómo usar este marco ligero
de JavaScript y su Model-View-ViewModel (MVVM) patrón. recurso para cualquier desarrollador
Aprenderá cómo construir su propio Datos, extender el marco con buscando hacer su
funciones reutilizables y trabajar con Un servidor para mejorar su
aplicación de cliente con persistencia. En la final Capítulo, usted usuario de la aplicación web
construirá un carro de la compra para ver cómo todo cabe juntos. experiencia pop
Si usted es un desarrollador web con experiencia en JavaScript, presenta las características
HTML y CSS, Usted está listo para Knockout. y beneficios de
■ Aprenda a crear un modelo de vista Knockout.js con
■ Enlazar HTML de datos y atributos y clases CSS y estilos ejemplos extensos y
■ Entender vinculantes en la jerarquía contexto del explicaciones en profundidad.
Knockouts de gracia de datos
■ Use las propiedades que cambian dinámicamente a través usted también se beneficia
de usuario Interacción del autor
■ Trabajar con las formas mediante el uso de varias recomendaciones y
ediciones diferentes
■ enlazar varios ViewModels en una sola página consejos procedentes de
■ Extender o adjuntar funciones personalizadas a los lecciones aprendidas
observables su experiencia en la construcción
■ Realizar las interacciones del lado del servidor con jQuery
■ Asignar un objeto JavaScript o aplicar los datos JSON a un aplicaciones web. “
-Steven Kennedy
nuevo objeto
Desarrollador Senior de Software en Fusebill
Jamie Munro
Knockout.js
De Jamie Munro
Publicado por O'Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
Los libros de O'Reilly se pueden comprar para uso educativo, comercial o de promoción de ventas. Las
ediciones en línea son También disponible para la mayoría de los títulos ( http://safaribooksonline.com ). Para
obtener más información, póngase en contacto con nuestra empresa / departamento de ventas institucionales:
800-998-9938 o corporate@oreilly.com.
El logotipo de O'Reilly es una marca registrada de la imagen de portada de un negro O'Reilly Media,
Inc. Knockout.js,Canguro de árbol, y el vestido comercial relacionado son marcas registradas de O'Reilly
Media, Inc.
Aunque el editor y el autor han utilizado esfuerzos de buena fe para garantizar que la Instrucciones contenidas
en este trabajo son exactas, el editor y el autor renuncian a toda responsabilidad por errores u omisiones,
incluyendo, sin limitación, responsabilidad por los daños resultantes del uso de O la confianza en este
trabajo. El uso de la información e instrucciones contenidas en este trabajo está en su propio riesgo. Si
cualquier muestra de código u otra tecnología que este trabajo contiene o describe está sujeto a código abierto
Licencias o los derechos de propiedad intelectual de terceros, es su responsabilidad asegurarse de que su uso
Cumple con dichas licencias y / o derechos.
Este libro está dedicado a mi familia. Espero que aprendas, como yo, que cuando
Trabajar duro y poner su mente a algo, usted puede lograr cualquier cosa!
Tabla de contenido
Prefacio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vii
7. observables potenciador. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Extendiendo observables 47
Adición de funciones personalizadas a 49
observables
Observaciones de limitación de la tasa 51
9. El Mapping Plugin. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Mapa desde un objeto 63
Mapa de JSON (o un servidor) 65
Observando e ignorando propiedades 68
específicas
Rara vez ves una actualización de página completa; En su lugar, el contenido se carga en
línea. Más importante, su contexto se mantiene y no se ven obligados a saltar entre varias páginas.
Un ejemplo perfecto de esto es Gmail. Irónicamente, vino de escribir este libro. yo era Revisar un
correo electrónico de mi editor y revisor técnico. Tengo el correo electrónico abierto Y quería
responder a ella. Debido a que Gmail colocó mi respuesta en línea, podría fácilmente Revisar el
correo electrónico y escribir mi respuesta al mismo tiempo, sin necesidad de saltar
O tienen dos ventanas abiertas.
KnockoutJS hace que la implementación de aplicaciones web como ésta sea rápida, eficiente y
Importante, fácil de mantener!
Instalación de KnockoutJS
KnockoutJS hizo su debut en julio de 2010. Fue lanzado como un código abierto Proyecto del autor
Steve Sanderson. Ahora está siendo mantenido por el código abierto comunidad. La versión 3.0 fue
lanzada a finales de 2013.
Puede descargar la versión minificada de Knockout haciendo clic derecho (Ctrl + Click para Mac)
y seleccionando la opción "Guardar enlace como ...".
Vii
Sugiero crear una nueva carpeta para todos los ejemplos de código de este libro. Dentro de eso
carpeta, crea una subcarpeta llamada js y coloque el archivo nocaut-3.2.0.js interior.
<script type='text/javascript'
src='js/knockout-<current-version>.js'></script>
Si desea utilizar la versión 3.2 como los ejemplos de este libro, puede visitar
el proyecto KnockoutJS en Github y apoderarse de su versión de elección.
Una vez descargado el framework Knockout, cree una página HTML que cargue el Marco, como
en Ejemplo P-1 .
<!DOCTYPE html>
<html>
<head>
<title>Installing KnockoutJS</title>
</head>
<body>
<script type='text/javascript' src='js/knockout-3.2.0.js'></script>
</body>
</html>
En el ejemplo anterior, incluí KnockoutJS justo antes de la etiqueta de body final. Esto es hecho
para permitir que el navegador web procese el HTML sin esperar el archivo JavaScript a descargar
y ejecutar.
Viii | Prefacio
Convenciones utilizadas en este libro
Itálico
Indica nuevos términos, direcciones URL, direcciones de correo electrónico, nombres de archivo y
extensiones de archivo.
Ancho constante
Se usa para listados de programas, así como dentro de párrafos para referirse a elementos del
programa. Nombres de variables o funciones, bases de datos, tipos de datos, variables,
declaraciones y palabras clave.
Este libro está aquí para ayudarle a hacer su trabajo. En general, si se ofrece código de ejemplo con
este libro, puede usarlo en sus programas y documentación. Tu no necesita ponerse en contacto con
nosotros para obtener permiso a menos que esté reproduciendo una porción significativa de el
código. Por ejemplo, escribir un programa que utiliza varios trozos de código de este libro no
requiere permiso. Venta o distribución de un CD-ROM de ejemplos
Prefacio | ix
De los libros de O'Reilly requiere permiso. Respondiendo a una pregunta citando esta Libro y
código de ejemplo de cotización no requiere permiso. Incorporando una Cantidad de código de
ejemplo de este libro en la documentación de su producto Requieren permiso.
Si usted siente que su uso de ejemplos de código cae fuera del uso justo o el permiso dado arriba,
no dude en contactar con nosotros en permissions@oreilly.com .
Safari Books Online ofrece una gama de planes y precios para la empresa , el gobierno ,la
educación , y los individuos.
Cómo contactarnos
X | Prefacio
Tenemos una página web para este libro, donde enumeramos erratas, ejemplos y cualquier
información. Puede acceder a esta página en http://bit.ly/knockoutjs-book .
Para comentar o hacer preguntas técnicas acerca de este libro, envía un correo electrónico
a bookques-tions@oreilly.com .
Para obtener más información sobre nuestros libros, cursos, conferencias y noticias, sitio
en Http://www.oreilly.com .
Expresiones de gratitud
¿Dónde empiezo? Pensé que escribir mi cuarto libro sería mucho más fácil que esoestaba. Mi
último libro se unió tan suavemente, y pensé que esto sería lo mismo. Definitivamente no era! En
cada etapa de este libro, me vi obligado a parar yPensar "¿Por qué estoy haciendo esto de una
manera particular?" Hay tantas cosas que hago conKnockout y JavaScript de cierta manera sin
pensar, que me vi obligado a pensar sobre las razones por las que lo hago de esta manera. Fue una
enorme experiencia de crecimiento personal y me siento como un desarrollador mucho mejor y
espero que estas lecciones se pasan a
todos y cada uno de ustedes.
Primero debo agradecer a mi esposa, Shannon. Ella ayudó inmensamente por ser tan buena mamá a
nuestros tres hijos pequeños -Lily, Owen y Kayla- mientras escribía este libro. Sin su amor y
apoyo, yo no dormiría en absoluto!
En segundo lugar, a Steve Kennedy (usted puede ver su nombre aparece de vez en cuando en
ejemplos). Pasamos muchos una hora de almuerzo pasando detalles minuciosos de casi cada
aspecto del libro. Se aseguró de que cada ejemplo fuera técnicamente preciso y aseguró que el "por
qué" estaba completamente cubierto. Espero que el "por qué" se hagan las cosas será
Inestimable a lo largo de este libro.
En tercer lugar, a Mike Wilson (mejor no intentar la dirección de correo electrónico en el ejemplo
9-4!). Mike realmente Ayudó a dar forma a los primeros capítulos para asegurar que nos dimos
bien a los ejemplos antes de presentar- La teoría. Como lector de muchos libros, esto siempre me
hace sentir mejor ver el resultados del ejemplo "Hello World" inmediatamente.
No puedo olvidar el equipo de O'Reilly. Gracias a Meg, Kara y Gillian por hacer de esto un
experiencia maravillosa.
Y, finalmente, para usted, el lector: Espero que disfrute leyendo este libro y aprenda tanto Como lo
hice de escribirlo!
Prefacio | Xi
CAPÍTULO 1
Introducción a KnockoutJS
KnockoutJS es una biblioteca JavaScript de código abierto. Fue construido para permitirle crear
aplicaciones web dinámicas y ricas. Está construido con el Modelo-Vista-ViewModel (MVVM)
patrón . Knockout hace que sea realmente sencillo implementar un usuario complejo Que responde
a las interacciones del usuario.
Me gusta Knockout porque es una de las bibliotecas JavaScript más livianas disponibles
hoy. Tampoco trata de ser un marco todo en uno. Sirve para un solo propósito: datos vinculando su
ViewModel a su interfaz de usuario.
Implementar Knockout implica tres cosas distintas: una vista que contiene HTML Y elementos
CSS que obtienen datos vinculados a él, un ViewModel que contiene los datos para vincular a la
vista, y decir Knockout para realizar la vinculación de datos a la vista con el ViewModel.
Los ejemplos de este capítulo muestran cómo crear una página HTML con una
ViewModel. Después de revisar la sintaxis básica de vinculación de datos, exploraremos la varips
tipos de ViewModels que funcionan con la vista.
El enlace de datos se lleva a cabo mediante la adición de un atributo HTML llamada de datos se
unen a cualquier elemento HTML que desea que Knockout sustituya con información de su
ViewModel.
A veces, una etiqueta HTML no funciona, por lo que Knockout también le permite especificar dato
enlaces con comentarios HTML, como se muestra en el Ejemplo 1-1 .
1
Ejemplo 1-1. Enlaces ocultos usando comentarios HTML
<!-- ko -->
<!-- /ko -->
Ejemplo 1-2 muestra la creación de un encabezado que mostrará la propiedad de name dentro de la
ViewModel.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<h1>Hello <span data-bind="text: name"></span></h1>
ko.applyBindings(viewModel);
</script>
</body>
</html>
Cuando se ejecuta este ejemplo en un navegador, emite Hello Steve Kennedy en el interior
una etiqueta h1.
Una span span está enlazado a datos a la propiedad nombre del modelo de vista. Esto se hace por
colocar texto: name dentro del atributo bind-data de HTML.
El tercero es decir Knockout para realizar la vinculación de datos de la vista y el ViewModel. Esto
se logra llamando a la función ko.applyBindings con un ViewModel.
Cuando se ejecuta esta función, Knockout procesa tanto la vista como la ViewModel. Todos los
enlaces de datos en la vista se ejecutan y se sustituyen dinámicamente por Los datos de
ViewModel.
Knockout no te limita a un solo ViewModel por vista. Grandes proyectos o clases que son bien
diseñados para la reutilización son razones comunes para vincular múltiples ViewModels a una
sola vista. Esto se discute con más detalle en Capítulo 6 .
¿Qué es MVVM?
El patrón de diseño Model-View-ViewModel (MVVM) se basa en gran medida en el Modelo Patrón
de vista controlador (MVC). De hecho, el MV se comparte entre ellos. Es el ViewModel que
realmente separa los dos.
MVVM fue diseñado para implementar la vinculación de datos entre su ViewModel y su vista. Esto
es lo que KnockoutJS hace por nosotros y lo hace muy bien. Se logra utilizando algunos atributos
HTML sencillos de implementar y un JavaScript ViewModel como se muestra en el Ejemplo 1-2 .
Lo más importante a recordar cuando se está construyendo ViewModels es que deben organizarse
para que sea fácil representar cómo usa su vista los datos. Exploramos varios escenarios comunes
en los próximos ejemplos.
Creación de un ViewModel
Un ViewModel puede ser cualquier tipo de variable JavaScript. En el Ejemplo 1-3 Empecemos con
un estructura simple JavaScript que contiene una sola propiedad llamada name.
var myFirstViewModel = {
name: 'Steve Kennedy'
};
Qué es MVVM | 3
El ViewModel anterior es bastante básico. ViewModels no se limitan a una simulación como
demuestran los ejemplos siguientes.
Normalmente, cuando creo ViewModels, creo clases de JavaScript simples o complejas Que me
permiten aprovechar un estilo de programación orientado a objetos (funciones, propiedades,
abstracción, etc.).
En el Ejemplo 1-4 , Creo un ViewModel que se construye con algún objeto básico de orientación
Que proporcionará más funcionalidad para nuestra vista.
self.getName = function() {
return self.name;
};
};
En este ejemplo, mi ViewModel es una función de JavaScript que he hecho para actuar como un
clase en OOP. Contiene la misma variable name que he creado en el anterior ejemplo pero esta vez
está encapsulada en mi clase y actúa como una propiedad de ella.
También he añadido una nueva función llamada getNombre que me permite acceder a mi
propiedad de name sin llamar a mi propiedad de clase directamente desde otras partes de mi
código.
Aunque el código resultante entre Ejemplo 1-4 y Ejemplo 1-3 se ven muy diferente de hecho, son
bastante similares. La propiedad name se puede acceder en el exacto misma forma ya sea de
ejemplo, como se muestra en el Ejemplo 1-5 .
alert(myFirstViewModel.name);
En los Ejemplos 1-3 y 1-4 , La propiedad name fue codificado en un valor. En muchos escenarios,
los datos de este tipo se cargarían de una fuente diferente: una base de resultados de una llamada
AJAX, etc.
function ViewModel(name) {
var self = this;
self.name = name;
self.getName = function() {
return self.name;
};
};
En los Ejemplos 1-3 y 1-4 , la clase ViewModel fue asignado directamente a la variable. Este
ejemplo es ligeramente diferente en que una función (que actúa como una clase) llamó View
Model se crea que acepta la propiedad de name. Esta clase es entonces instanciada por pass- El
nombre en el constructor.
ViewModels con parámetros | 5
En todos los ejemplos futuros, seguiré usando las clases de JavaScript ya que proporcionan mucho
más flexibilidad. Sin embargo, si una simple variable o estructura de JavaScript será suficiente para
su opinión, no sienten la necesidad de envolver su ViewModel en una clase.
En el Ejemplo 1-1 , texto fue datos, unidos a una span tags. Al igual que el texto, es bastante
común contenido de data-bind que contiene datos HTML.
En el Ejemplo 2-1 , La función getName se amplía para envolver la salida del name Enlace de
datos con algún código HTML.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
7
<script type='text/javascript' src='js/knockout-3.2.0.js'></script>
<script>
function ViewModel() {
self.getName = function() {
return 'Hello <em>' + self.name + '</em>!';
};
};
Ejecución de Ejemplo 2-1 sería la salida de un mensaje similar al Ejemplo 1-1 , con la excepción
que el nombre estaría en cursiva debido a la etiqueta HTML alrededor de la salida- puesto de
la propiedad name.
Knockout puede enlazar casi cualquier atributo HTML, clase CSS o estilo CSS. Estos son hecho de
forma bastante similar a los enlaces de text y html con la excepción de que pueda Especifique más
de una propiedad a la vez. Esto se logra envolviendo el Propiedades en corchetes como en
Ejemplos 2-2 y 2-3 .
<p data-bind="
style: { marginBottom: 0, paddingBottom: '1em' }, css: 'myClass'">
This text has custom styles and a CSS class.</p>
El siguiente ejemplo agrega dos estilos personalizados a la etiqueta p. Observe cómo el estilo
propiedades margin-bottom y el paddind-bottom son camelCase en lugar de con guión.
Mediante la colocación de una coma después de la llave de cierre rizado, he añadido un segundo
enlace de datos a la etiqueta p. Esta vez que establece una clase CSS de myClass.
La adición de atributos HTML se realiza de manera similar. En Ejemplo 2-3 , Un atributo id está
agregado.
Al igual que en el Ejemplo 2-2 , si quería unirse atributos HTML adicionales, pude colocar una
coma antes de la llave de cierre rizado y agregar propiedades adicionales.
Cuando se define un enlace de datos, es posible que desee especificar una condición que cuando
sus datos contienen un valor específico, que genera un nombre de clase diferente. Esto puede ser
logrado mediante la colocación de declaraciones condicionales dentro de su vinculación de datos
(data binding).
En el Ejemplo 2-4 , se crea un botón. El enlace de datos de text contiene un condicional afirmación
de que cuando el ID es 0, el texto del botón dice “Create”. Sin embargo, cuando el id es mayor que
0, dirá “Update”, lo que permite el uso de una sola etiqueta buttom que cambia dinámicamente.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
self.id = 0;
};
ko.applyBindings(viewModel);
</script>
</body>
</html>
Para que este ejemplo funcione, el ViewModel se ha actualizado para incluir una nueva propiedad
llamado id. Al establecerlo en 0, cuando este ejemplo se muestra en un navegador web, el buttom
de texto dirá: “Crear” (create). Con la actualización de la identificación que desea cualquier otro
número positivo, el texto cambiará a decir "Actualizar" (update).
Al igual que cuando se utilizan enlaces de datos, los enlaces condicionales se pueden
Utilizando una función en lugar de colocar la condición dentro de la vinculación de datos, como se
muestra en Ejemplo 2-5 .
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<button type="submit" data-bind="text: (isNew()) ? 'Create' : 'Update'">
</button>
self.id = 1;
self.isNew = function() {
return id == 0;
};
};
ko.applyBindings(viewModel);
</script>
</body>
</html>
El modelo de vista se actualiza en el ejemplo, para añadir una nueva función llamada isNew. Esta
contiene la misma instrucción condicional que se utilizó en el Ejemplo 2-4 . Los datos la
vinculación también se actualizó para utilizar la función dentro de la instrucción de condición.
El id se actualiza de 0 a 1, por lo que la ejecución de este ejemplo salidas “update” para la buttom
de texto.
Knockout mantiene una jerarquía padre / hijo de contextos. Cuando accedes propiedades a los datos
se enlazan, todo es relativo al contexto en el que se encuentran. La raíz (root) del contexto es el
viewModel que se suministra a la función ko.applyBindings.
Todo es relativo al contexto actual, por lo que los enlaces de text utilizan el name de la propiedad
sin el prefijo del viewModel.
En los siguientes ejemplos, algunos de los nuevos enlaces de datos crean un contexto secundario
bajo el contexto raíz.
Knockout ofrece varias variables útiles que le permiten navegar entre los texto que está en un padre
o incluso el contexto raíz:
$ Root
Esto accede al contexto raíz (el ViewModel está vinculado a Knockout) en cualquier
texto. Esto es útil cuando no está seguro de cuántos contextos parent/ child están por encima
el que está actualmente.
$parent
Cuando se encuentre en un contexto secundario, accederá al padre directo del contexto
actual.
$parents
Esto es similar a la variable $ parent, excepto que contiene una serie de contexto al contexto
en el que se encuentran actualmente en. Los $parents[0] es el mismo
que $parent. Similarmente, usando los $parents [$ parents.length - 1] es lo mismo que
usar $root.
$data
Esto proporciona acceso al objeto actual en el que se encuentra tu contexto. Esto es muy útil
cuando usted está en un contexto que es una variable y no contiene propiedades.
11
$index
Esto sólo está disponible dentro de la unión foreach y contiene un número entero que
representa la posición actual del bucle comenzando en 0 y llegando a la longitud -1.
La unión foreach binding se utiliza para repetir una sección de HTML en una matriz de
objetos. En Ejemplo 3-1 , una lista de libros que he escrito se muestra en una lista desordenada.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<ul>
<!-- ko foreach: books -->
<li data-bind="text: $data"></li>
<!-- /ko -->
</ul>
self.books = [
'Rapid Application Development With CakePHP',
'20 Recipes for Programming MVC 3: Faster, Smarter Web Development',
'20 Recipes for Programming PhoneGap:
Cross-Platform Mobile Development for Android and iPhone'
];
};
ko.applyBindings(viewModel);
</script>
</body>
</html>
Ejemplo 3-1 tarda varias cosas primeras que se han mencionado y los muestra en acción.
El foreach binding no estaba destinada a una etiqueta HTML; En su lugar, se coloca dentro
comentarios HTML. Me parece muy conveniente cuando se usa foreach binding porque evita un
elemento innecesario para envolver el HTML que quiero repetir para cada uno elemento en la
matriz.
Otro uso común para la foreach binding es para mostrar una lista en una tabla HTML.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<table>
<thead>
<tr>
<th>Title</th>
<th>ISBN</th>
<th>Published</th>
</tr>
</thead>
<tbody data-bind="foreach: books">
<tr>
<td data-bind="text: title"></td>
<td data-bind="text: isbn"></td>
<td data-bind="text: $parent.formatDate(publishedDate)"></td>
</tr>
</tbody>
</table>
self.books = [
{
title: 'Rapid Application Development With CakePHP', isbn: '1460954394',
publishedDate: '2011-02-17'
}, {
title: '20 Recipes for Programming MVC 3: Faster, Smarter Web
Development',
isbn: '1449309860', publishedDate: '2011-10-14'
}, {
foreach Binding | 13
title: '20 Recipes for Programming PhoneGap:
Cross-Platform Mobile Development for Android and iPhone', isbn: '1449319548',
publishedDate: '2012-04-06'
}
];
self.formatDate = function(dateToFormat) {
var months = new Array("January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December");
Ejemplo 3-2 introduce varias nuevas cosas así. En primer lugar, el modelo de vista ya no es siendo
asignado directamente a una variable. Ahora se crea una instancia como una clase, y luego pasa la
variable resultante a la ko.applyBindings función.
La “fecha de publicación” td etiqueta es ligeramente diferente a los dos anteriores. Siendo los datos
vinculados (databound) a una función que acepta una fecha como parámetro. Debido a que la
función no está contenida dentro del books array, se necesita acceder mediante el $parent variables
porque está fuera del contexto actual.
Como código se refactorizado en el futuro, puede encontrarse con que su existente HTML se
reutiliza en un contexto diferente, donde $root puede no ser lo mismo que $parent, y esto le
da menos posibilidades de acceder a la contexto equivocado.
El foreach unión contiene varios métodos de devolución de llamada que pueden ser ejecutadas por
Knockout después de ciertos eventos ocurren:
afterRender
Esto se llama cuando el foreach termina primero inicializar y cada vez es un elemento
añadido a la matriz.
afterAdd
Esto se llama cada vez que se añade un elemento al a array. A diferencia de afterRender,
esto es no se llama cuando el array se inicializa primero.
beforeRemove
Esto se llama cuando un elemento se retira del array. Esto se utiliza a menudo para animar
una la eliminación de un elemento.
beforeMove
Esto se llama cuando un elemento se mueve dentro del array. Es otra gran oportunidad para
comenzar una animación o añadir un efecto al elemento que se está interactuado con.
afterMove
Esto se llama después de que el elemento se mueve dentro del array. Al igual que
el beforeMove, este sería la oportunidad de terminar cualquier efecto sobre el elemento
movido.
Para demostrar cómo se utiliza una de estas devoluciones de llamada, en el Ejemplo 3-3 , voy a
mejorar Ejemplo 3-2 para incluir una imagen. El afterRender buscará la imagen del servidor para
ayudar a prevenir que el bloqueo de la página que se queden mientras se carga una imagen.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
15 | foreach Callbacks
<body>
<table>
<thead>
<tr>
<th>Thumbnail</th>
<th>Title</th>
<th>ISBN</th>
<th>Published</th>
</tr>
</thead>
<tbody data-bind="foreach: { data: books, afterRender: loadImage }">
<tr>
<td><img src="images/loading.gif" data-bind= "attr { id: 'image_' +
isbn }" /></td>
<td data-bind="text: title"></td>
<td data-bind="text: isbn"></td>
<td data-bind="text: $parent.formatDate(publishedDate)"></td>
</tr>
</tbody>
</table>
self.books = [
{
title: 'Rapid Application Development With CakePHP', isbn: '1460954394',
publishedDate: '2011-02-17', image:
'http://ecx.images-amazon.com/images/I/41JC54HEroL._AA160_.jpg'
}, {
title: '20 Recipes for Programming MVC 3: Faster, Smarter Web
Development',
isbn: '1449309860', publishedDate: '2011-10-14',
image:
'http://ecx.images-amazon.com/images/I/51LpqnDq8-L._AA160_.jpg'
}, {
title: '20 Recipes for Programming PhoneGap:
Cross-Platform Mobile Development for Android and iPhone', isbn: '1449319548',
publishedDate: '2012-04-06', image:
'http://ecx.images-amazon.com/images/I/51AkFkNeUxL._AA160_.jpg'
}
];
self.formatDate = function(dateToFormat) {
var months = new Array("January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December");
Ejemplo 3-3 es bastante similar al Ejemplo 3-2 en términos de estructura, con varios importantes
cambios.
En primer lugar, los foreach binding se ha modificado para incluir el afterRender y volverlo a
llamar. Se llamará a la función loadImage.
En segundo lugar, la tabla se actualiza para incluir una nueva columna para la thumbnail
(miniatura). Por defecto, Pongo una imagen de marcador de posición en su lugar. Luego, utilizando
un atributo binding (enlace), puse la identificación de la imagen para incluir un identificador único
que se utilizará para intercambiar la imagen.
En tercer lugar, la matriz(array) books fue actualizado para incluir una nueva propiedad
llamada image que contiene la ruta completa a la imagen del libro en Amazon.
Y, por último, la loadImage se creó función. Este utiliza un poco de jQuery para el acceso la
imagen por el ID único que creó, y cambia la fuente de la imagen a la ubicación proporcionada en
el libros de matriz (books array).
Para que este ejemplo funcione correctamente, es necesario descargar la librería jQuery . Una vez
descargado, lo coloca dentro de la creada anteriormente js carpeta. Por simplicidad, renombrado el
archivo jquery.js. No dude en dejarlo como está, pero asegúrese de actualizar la ubicación al
archivo en el código HTML.
with Binding
El with binding es similar a la foreach binding ya que crea un nuevo child (hijo) contexto. Todo
dentro de la vinculación (binding) es ahora en relación con la variable a la cual es ligado. La
principal diferencia entre los dos es que con es un objeto individual con multiples propiedades,
mientras que el foreach repite el HTML en la unión (binding).
with Binding | 17
Ejemplo 3-4 amplía la lista de libros(books) para ser una sola página de detalles del libro y
apalancamientos el de la unión (binding) para evitar que los prefijos repetitivos de la variable libro
(book).
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<div id="book" data-bind="with: book">
<h1 data-bind="text: title"></h1>
<h2>Published on <span data-bind="text: $parent.formatDate(publishedDate)">
</span></h2>
<p data-bind="text: synposis"></p>
</div>
self.book = book;
self.formatDate = function(dateToFormat) {
var months = new Array("January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December");
var book = {
title: 'Rapid Application Development With CakePHP', synposis: '...',
isbn: '1460954394', publishedDate: '2011-02-17'
};
ko.applyBindings(viewModel);
</script>
</body>
</html>
A diferencia del foreach vinculante (binding), el HTML no se repite, ya que sólo hay un solo book
para mostrar.
En comparación, como se muestra en el ejemplo 3-5 , si usted no ha utilizado el with data binding,
el mismo resultado podría lograrse con el siguiente código HTML.
<div id="book">
<h1 data-bind="text: book.title"></h1>
<h2>Published on <span data-bind="text: formatDate(book.publishedDate)">
</span></h2>
<p data-bind="text: book.synposis"></p>
</div>
Cuando with binding (la unión, el enclace) no se utiliza, observe cómo los elementos HTML son
enlazados a datos utilizando la ruta de la variable completa (por ejemplo, book.title ). La otra
diferencia es que el formato Fecha de la función ya no tiene que llevar el prefijo $ parent debido a
un contexto hijo (child) no fue creado, y todavía lo es en el contexto de la raíz (root).
En situaciones como esta, utilizando with binding (la unión, el enclace) es un simple conveniencia
de evitar repetición y anteponiendo las propiedades secundarias con la variable.
With binding | 19
CAPÍTULO 4
Modificación de las propiedades dinámicamente
Hasta ahora, sólo hemos tocado en un pequeño trozo del framework KnockoutJS. En este capítulo,
vamos a empezar a tomar ventaja de las propiedades que cambian dinámicamente a través la
interacción del usuario.
Knockout llama a estas propiedades observables. Cuando se define una variable o propiedad como
un observable, Knockout rastrea cuando cambia. Esto se puede utilizar en una variedad de
diferentes formas que veremos en los próximos capítulos.
La definición de un observable
Hay tres tipos diferentes de observables que se utilizan con mayor frecuencia. El primero, se
muestra en el Ejemplo 4-1 , Es una variable observable.
alert(myObservable());
Para crear un observable, asignar la funcion ko.observable de la variable. por defecto un valor se
puede especificar en el constructor de la llamada. Knockout luego se convierte en sus variables en
una función y pistas cuando cambia el valor, con el fin de notificar a la interfaz de usuario
elementos asociados con la variable.
21
Accesanco a un Observable
Después de definir un observable, tiene que ser llamado como una función con el fin de
obtener o establecer su valor. Si intenta establecer directamente como si se eran una
variable, lo observable serían destruidos.
En Ejemplo 4-1 , observe cómo el valor de la variable se realiza como una función. Al
acceder al valor de la alerta declaración, esto es también hecho. Si se va a tratar de alertar al
observables sin los soportes, se emitiría una gran porción de código JavaScript que contiene
la implementación de la función observable Knockout.
El segundo tipo de observable, como se muestra en el Ejemplo 4-2 , Es una matriz observable
(observable array).
En el Ejemplo 4-2 , la matriz se instancia como una matriz vacía haciendo pasar dos cuadrados
soportes en el constructor.
Al igual que las variables observables, cuando se añaden o eliminan elementos de la matriz,
Knockout notifica elementos que se ha suscrito a las notificaciones.
Una matriz observable es ideal para uso con mesas donde los elementos están siendo
dinámicamente añadido y eliminado.
self.firstName = ko.observable('Steve');
self.lastName = ko.observable('Kennedy');
self.fullName = ko.computed(function() {
return 'Hello ' + self.firstName() + ' ' + self.lastName();
});
Una vez que el modelo de vista está obligado a Knockout, se ejecuta la función computarizada. Por
cada uno puede observar que se utiliza dentro de esa función, se suscribe a ningún cambio a
eventos Esa variable. Cuando se cambia, Knockout sabe que la variable calculada debe estar
actualizada.
Un ejemplo común de cuándo utilizar este tipo de observable es en el Ejemplo 4-3 , donde el
nombre y apellido se concatenan en un computed observables.
self.firstName = ko.observable('Steve');
self.lastName = ko.observable('Kennedy');
self.fullName = ko.pureComputed(function() {
return 'Hello ' + self.firstName() + ' ' + self.lastName();
});
Los observables son tratados de manera diferente porque cuando no hay elementos de escucha de
cambios en la variable calculada, que se colocan en dormir modo versus listening modo. Mientras
que en el modo de dormir, Knockout dispone todas las dependencias y reevalúa el contenido
cuando se escucha a diferencia de modo de lectura, que gestiona las referencias a todos los
suscriptores y asegura el valor es de hasta al día antes del primer acceso.
El ejemplo anterior se deduce ambas reglas para ser una pura función:
La segunda regla es probablemente el más importante a la hora de decidir si se debe utilizar una
computed o una pureComputed observable con Knockout. Dentro de su observables, si necesita
ejecutar otro código, a continuación, se debe utilizar un observables calculada para asegurar que
esté en modo de escucha en lugar del modo de dormir. Vea la diferencia en Ejemplo 4-5 .
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
pureComputed observables | 23
self.firstName = ko.observable('Steve');
self.lastName = ko.observable('Kennedy');
self.pureComputedExecutions = 0;
self.computedExecutions = 0;
self.pureComputedFullName = ko.pureComputed(function() {
// This is not recommended
self.pureComputedExecutions++;
return 'Hello ' + self.firstName() + ' ' + self.lastName();
});
self.computedFullName = ko.computed(function() {
self.computedExecutions++;
return 'Hello ' + self.firstName() + ' ' + self.lastName();
});
};
Ejemplo 4-5 rompe la regla pura función mediante la colocación de un efecto secundario dentro de
ella; sin embargo, que está demostrando la diferencia entre el la espera (sleep) y el modo de
escucha.
Cuando se ejecuta este ejemplo, después de que el ViewModel se ha unido a la vista, dos alerta los
mensajes se muestran que muestran el número de veces que las funciones pureComputed y
Computed se llaman.
Debido a que los computed observables no están enlazados a datos (data-bound), el pureComputed
está en el modo de dormir (sleep); por lo tanto, la función computed nunca ha sido visitada, y el
contador está a 0. Sin embargo, la función computed se evalúa automáticamente en los data-
binding (dato vinculante) para establecer sus oyentes, haciendo que el contador se incremente a 1.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<button type="button" data-bind="click: updateObservable">Click me</button>
self.showExtraData = ko.observable(false);
self.updateObservable = function() {
self.showExtraData(!self.showExtraData());
};
};
Vamos a empezar con el código HTML. Un buttom se crea y datos enlazados a un evento, haga
click. Cuando el usuario hace clic en el botón, Knockout llama a la función updateObservable.
Debajo del buttom es un div etiqueta. Este elemento está utilizando el visible data binding. Cuando
el resultado de la condición es false, el elemento está oculto. Cuando se cambia a true, se hace
visible.
A continuación, vamos a explorar el ViewModel de JavaScript. La primera cosa que hice fue crear
una variable observable llamada showExtraData y por defecto a false (oculto por defecto). Y, por
último, la updateObservable se define la función, que llama cuando Knockout se hace clic en el
botón. Esta función simplemente inversa al valor de la variable showExtraData. La primera vez que
se hace clic en el botón, el código HTML dentro del div se revela. Si se hace clic de nuevo, el texto
se oculta de nuevo.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<button type="button" data-bind="click: updateObservable">Click me</button>
self.showExtraData = ko.observable(false);
self.updateObservable = function() {
Ejemplo 4-7 es casi idéntico al Ejemplo 4-6 ; De hecho, el viewModel es JavaScript Sin tocar El
HTML contiene la ligera diferencia. En lugar de la div que contiene un data para los data binding
para visible, he utilizado el if de los data binding dentro de un comentario HTML.
Si inspecciona el código HTML cuando se carga la página, se dará cuenta de que la div etiqueta es
por ningún lado. Al hacer clic en el botón hará que el código HTML para ser dinámicamente
insertado en el DOM.
Si se añade un elemento a la DOM a causa de un usuario interacción que tenían uno o más
efectos secundarios de JavaScript realizan en él durante la carga de la página original, éstos
tendrían que ser ejecutado después de añadir de nuevo a la DOM.
Por ejemplo, si usted tiene un campo que está vinculado a una fecha jQuery Picker,
JavaScript es necesario para inicializarlo. Esto tiene que ser ejecutado después se añade el
elemento al DOM.
En un escenario de este, que podría ser más prudente utilizar el visible el enlace de datos
(data-binding) debido a que los elementos permanecerán en el DOM y puede ser inicializado
en la carga del documento.
Encuentro utilizando los if y ifnot data-binding muy conveniente cuando quiero quitar contenido
que sólo quiero que el usuario sea capaz de acceder en escenarios específicos.
ifnot: !showExtraData()
Ejemplo 4-7 podría lograrse usando ifnot mediante la actualización de la unión (binding) para
invertir la condición. En lugar de añadir los elementos cuando la condición se evalúa como true,
la ifnot añade los elementos cuando la condición se evalúa como false.
Cuando un observable se define primero, Knockout inicializa la variable como una función de
realizar un seguimiento de los cambios en el valor. Este contiene una cierta cantidad de
procesamiento gastos generales.
Es importante tomar decisiones conscientes sobre lo que usted define como un observable. Si el
valor puede cambiar potencialmente (mediante programación o de la interacción del usuario), una
propiedad observable es completamente válido. Sin embargo, si tiene cuatro propiedades y sólo dos
de ellos va a cambiar, y las otras propiedades son necesarias pero nunca cambiar, no hay necesidad
para que sean observados (ver Ejemplo 4-9 ).
function ViewModel(person) {
var self = this;
self.person = {
id: person.id,
firstName: ko.observable(person.firstName), lastName:
ko.observable(person.lastName), status: person.status
};
};
var person = {
id: 1,
firstName: 'Steve', lastName:
'Kennedy',
Ejemplo 4-9 implica que sólo puedo cambiar el nombre y apellido de un objeto person. La id y el
status no se puede cambiar; Sin embargo, todavía se pueden utilizar en Knockout el enlace de datos
(data-binding) con fines de exhibición.
Todos estos enlaces (binding) Knockout lo llama two-way binding. Esto significa que cuando se
cambia el elemento de formulario, su propiedad ViewModel se actualiza y si cambias mediante
programación la observable, el elemento de binding se engancha a ser actualizado
automáticamente.
31
Ejemplo 5-1. La unión textInput
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
self.myText = ko.observable('');
self.maxCharacters = 140;
self.charactersRemaining = ko.computed(function() {
return self.maxCharacters - self.myText().length;
});
};
Esto se puede solucionar porque el value de la binding ofrece una propiedad secundaria llamada
valueUpdate . Esto se puede ajustar a cualquier otro evento que Knockout debe escuchar en para
desencadenar cambios.
Ejemplo 5-2 dice Knockout para actualizar el valor cuando el evento afterkeydown es activado, que
proporcionará actualizaciones más instantáneas. Por defecto, cuando se utiliza el valor vinculante
(binding), Knockout solamente está detectando el onchange evento.
La submit que la unión (binding) se utiliza en la form del elemento y se activa cuando una
forma es presentada.
El click de unión (binding) se utiliza comúnmente en los botones y enlaces, pero se puede
aplicar a cualquier elemento DOM que es visible.
El hasFocus unión (binding) se utiliza comúnmente en la entrada de elementos y está
activado cuando el elemento DOM recibe la atención al usuario.
El event de unión permite especificar cualquier otro evento DOM (incluyendo el hacer
click y submit fijaciones), como al pasar el mousemover, keypress, etc.
Ejemplo 5-3 es bastante similar a un ejemplo anterior donde se visualiza una lista de libros del
array. El ejemplo se ha reducido hasta sólo incluir un título y una imagen.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<ul>
<!-- ko foreach: books -->
<li data-bind="text: title, event: { mouseover: $parent.loadImage }"></li>
<!-- /ko -->
</ul>
Los libros se imprimen en una lista desordenada. El li elemento se une a la de la propiedad del
title. Después de que el text binding, un event de unión(binding) se utiliza y se detecta el mouse
over event.
Cuando se activa este evento, llama a la función loadImage. Esta función llena una imagen con el
valor de la image de la propiedad.
La suscripción a los observables le permite realizar fácilmente los efectos secundarios a otra
propiedades en su modelo de vista cuando cambia el valor de la propiedad (ver Ejemplo 5-4 ). Los
ejemplo siguientes muestran esto con dos listas desplegables. Cuando el observado valor a partir de
los primeros cambios de la lista, que se actualiza de forma dinámica el valor observado de la
segunda lista.
La segunda lista contiene los estados disponibles para el país seleccionado. Por defecto, esta se se
oculta hasta que se seleccione un país que contiene una matriz de estados.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
self.selectedCountry = ko.observable();
self.selectedState = ko.observable();
self.availableCountries = ko.observableArray([
{
id: 1, name: 'United States', states: [
{ id: 1, name: 'Alabama' },
// ...
]
},
{
id: 2, name: 'Canada', states: [
{ id: 53, name: 'Alberta' },
// ...
]
}
]);
self.availableStates = ko.observableArray([]);
self.selectedCountry.subscribe(function() {
self.availableStates([]);
};
El conjunto de los países se llena con una id, name, y la propiedad del states. El array de estados se
utilizan para rellenar los estados disponibles cuando se selecciona ese país de la lista dwop-down.
Mediante la implementación de la validación discretas formas, todo esto puede ocurrir antes de la
forma siendo presentado. Hay un excelente plugin de jQuery que permite una fácil adición de
validación del lado del cliente discreta.
Ejemplo 5-5 muestra cómo configurar y incluir varios une forma de datos simples, incluyendo
el submit enlazar datos (data binding).
Para empezar, visite el jQuery Validación Plugin página web y descargar el plugin. Esta ejemplo
utiliza versión 1.13. Este plugin también requiere la biblioteca jQuery para ser instalado. Esto
puede ser descargado desde el sitio de jQuery o la lib carpeta en la validación de jQuery descarga.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
self.validate = function(form) {
return $(form).validate();
};
};
Ejemplo 5-5 crea un formulario que recoge un primer nombre, apellido y dirección de correo
electrónico. Estos campos son todos los datos enlazados a campos en el ViewModel
correspondiente.
El formulario también contiene un enlace a los datos de la submit binding que le dice a Knockout
llamar al validar la función que se ha creado en el viewModel.
Los tres campos de formulario que se hayan marcado required y debido a que se especifica el
campo email de tipo email, la validación de formularios asegura que tengo un email válido.
Knockout hace esto muy fácil. Hay un segundo parámetro opcional que puede ser pasado
al ko.applyBindings función que le dice a golpe de gracia para limitar su unión dentro de este
bloque de HTML.
Ejemplo 6-1 se ve casi lo mismo que algunos de los ejemplos anteriores, donde un simple nombre
estaba siendo obligado. Hay algunas diferencias sutiles que conseguir que esto funcione.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<div id="viewModel1">
<h1 data-bind="text: name"></h1>
</div>
<div id="viewModel2">
<h1 data-bind="text: name"></h1>
</div>
39
<script type='text/javascript' src='js/knockout-3.2.0.js'></script>
<script>
function ViewModel(name) {
var self = this;
self.name = name;
};
En primer lugar, hay dos h1 etiquetas colocadas dentro de su propio div etiqueta. Esta div etiqueta
contiene una Identificación del atributo que es importante para que este ejemplo funcione
correctamente.
En el JavaScript, el mismo modelo de vista se crea una instancia dos veces, cada uno con una
diferente nombre que la de entrada. Esta variable se hace pasar a continuación a
las ko.applyBindings como normal; sin embargo, esta vez un segundo parámetro se pasa
también. El div elemento se pasa por lo Knockout solamente se unirá dentro de ese elemento.
Puede confirmar esto copiando una de las h1 etiquetas y colocarlo fuera del div . Sin texto se
mostrará a causa del golpe de gracia no realiza ninguna enlaces de datos.
TinyMCE. TinyMCE convierte cualquier ordinaria textarea en un editor HTML sofisticado. Por
desgracia, TinyMCE en realidad no cambia el contenido del textarea a que se aplican,
el value vinculante (binding).
En el ejemplo 6-2 , textarea será atado a una costumbre Knockout unión llamada tinymce. Cuando
el usuario trabaja con el editor, una vista previa en vivo está vinculado a un div etiqueta usando
el html vinculante. Un botón también está ligado a una función que se restablecerá las contenidas
del editor para nada.
<!DOCTYPE html>
<html><head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<form>
<textarea data-bind="tinymce: htmlText"></textarea>
</form>
<h2>Preview</h2>
<div data-bind="html: htmlText"></div>
self.htmlText = ko.observable();
self.resetContent = function() {
self.htmlText('');
};
};
Hasta ahora, esto se ve idéntica a muchos ejemplos anteriores muestran. textarea está obligado a
una propiedad llamada htmlText . El botón está ligada a una función llamada resetContent, que
simplemente se establece el htmlText propiedad a una cadena vacía. La vista previa es un div que
se dirigía a los datos a través de la html unión al mismo htmlText propiedad.
ko.bindingHandlers.tinymce = {
init: function (element, valueAccessor, allBindingsAccessor) {
var tinymceOptions = { setup: function (editor) {
editor.on('change', function (event) {
valueAccessor()(event.target.getContent());
});
}
};
setTimeout( function() {
$( element ).tinymce(tinymceOptions);
}, 0 );
if ( tinymce ) {
if ( tinymce.getContent() !== value ) {
tinymce.setContent( value );
}
}
}
};
Para empezar, se dará cuenta de que dos propiedades se definen para la tinymce vinculante: init
y update.
En la configuración de TinyMCE, creé una función de configuración en línea que detecta el cambio
evento que se trigged por TinyMCE. Cada vez TinyMCE dispara el change event, el observable
que se une a la unión de encargo se actualiza con el contenido del editor TinyMCE.
La update propiedad se activa cada vez que los cambios observables a través de código (es decir, en
el ejemplo anterior, a partir clic en el botón de reinicio). Dentro de esta función, se obtiene el editor
TinyMCE que el observables está obligado a y establece el contenido de TinyMCE a el valor actual
de lo observable.
Incluso si usted no utiliza una plantilla, la funcionalidad subyacente convierte el golpe de gracia
Estructura HTML en foreach, with, y if fijaciones en una sola.
En el Ejemplo 6-4 , Voy a actualizar un ejemplo del Capítulo 3 que da salida a una lista
de libros en una mesa. El código HTML que se repite dentro del foreach vinculante será
se extrajo en una plantilla, lo que permite una fácil reutilización.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<table>
<thead>
<tr>
<th>Title</th>
<th>ISBN</th>
<th>Published</th>
</tr>
</thead>
<tbody data-bind="template: { name: 'book-template', foreach: books }">
</tbody>
</table>
<script>
function ViewModel() {
var self = this;
self.books = [
{
title: 'Rapid Application Development With CakePHP', isbn:
'1460954394',
publishedDate: '2011-02-17'
}, {
title: '20 Recipes for Programming MVC 3: Faster,
Smarter Web Development',
isbn: '1449309860', publishedDate: '2011-10-
14'
}, {
title: '20 Recipes for Programming PhoneGap:
Cross-Platform Mobile Development for Android and iPhone', isbn:
'1449319548',
publishedDate: '2012-04-06'
}
];
self.formatDate = function(dateToFormat) {
var months = new Array("January", "February", "March", "April", "May",
"June", "July", "August", "September", "October", "November", "December");
Este ejemplo es casi idéntico al ejemplo anterior con dos modificaciones principales.
En primer lugar, el foreach unión está envuelto dentro de una template de unión. la plantilla
encuadernación Indica Knockout para llamar al book-template para cada elemento en el foreach
Unión (binding).
Extendiéndose observables
Observables por sí solas pueden lograr un poco. Por supuesto, hay momentos con cada marco que
simplemente no puede hacer todo lo que desee. knockout ofrece la capacidad de escribir funciones
personalizadas para extender cualquier observable.
Ejemplo 7-1 se extenderá (juego de palabras) del ejemplo anterior que contaba caracteres para
evitar la entrada de texto de entrar en más de la cantidad asignada.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
self.maxCharacters = 140;
self.myText = ko.observable('')
.extend({maxCharacters: self.maxCharacters});
47
self.charactersRemaining = ko.computed(function() {
};
ko.applyBindings(viewModel);
</script>
</body>
</html>
return result;
};
La función de extensión es similar a los observables calculados en que se trata de tanto la lectura y
la write de la observable que se está extendiendo.
En la parte superior de la jerarquía es el suscribable clase; todos los tipos de observables heredan
de esta clase. Si desea agregar una función personalizada que está disponible para cualquier
observación Tipo ble, se uniría a esta clase.
En el ejemplo 7-3 , los libros están de vuelta. Esta vez, una lista de libros se mostrará en una lista
desordenada. Cada libro contiene una casilla de verificación que está enlazado a datos a la owned
propiedad observable del libro.
A continuación se añade una función al observableArray llamada booksOwned que creará una
nueva lista de los principales books de matriz que contiene solamente los libros donde la
propiedad owned es true.
a continuación, se muestra esta lista en una lista desordenada separada que muestra todos los libros
tu posees.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
List of books
<ul>
<!-- ko foreach: books -->
<li>
<input type="checkbox" data-bind="attr: { id: isbn }, checked: owned "/>
<label data-bind="attr: { for: isbn }, text: title"></label>
self.books = ko.observableArray([
{
title: 'Rapid Application Development With CakePHP', isbn:
'1460954394',
owned: ko.observable(false)
}, {
title: '20 Recipes for Programming MVC 3: Faster,
Smarter Web Development',
isbn: '1449309860',
owned: ko.observable(false)
}, {
title: '20 Recipes for Programming PhoneGap:
Cross-Platform Mobile Development for Android and iPhone', isbn:
'1449319548',
owned: ko.observable(false)
}
]);
return matchingItems;
}, this);
};
Esta función crea dos matrices: allItems y matchingItems. allItems contiene la matriz original. Esta
matriz es entonces enrollada a través, y el uso de las entradas a esta función, el elemento de la
matriz se compara con el valor esperado. Si hay un partido, que se añade a la segunda
matriz, matchingItems. Entonces se devuelve esta matriz.
Debido a que esta función se envuelve dentro de una función computarizada, que se ha configurado
para suscribirse a cualquier cambio en el observableArray o propiedades dentro de esa matriz que
son se observa. Así que cada vez que uno de los cambios, se ejecuta esta función, y la lista de libros
propiedad se actualiza.
Porque puede haber varias maneras diferentes que desea limitar, Knockout tiene previsto a algunos
métodos diferentes.
En su forma más simple, como se muestra en el Ejemplo 7-5 , Se puede ampliar el observable y
establecer un valor de tiempo de espera (en milisegundos) que debe esperar Knockout.
myObservable.extend( {
rateLimit: {
timeout: 1000,
method: "notifyWhenChangesStop"
}
});
En el Ejemplo 7-7 , Pensé que iba a estar ordenado para crear nuestra propia
autocompletar. Mediante el uso la Ratelimit cuando cambia el valor de retardo, una lista de los
lenguajes de programación se ser buscada. Cualquier coincidencia se añadirá a
un observableArray y se muestran en una lista desordenada.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
Tags Matching:
<ul>
<!-- ko foreach: matchedTags -->
<li data-bind="text: $data"></li>
<!-- /ko -->
</ul>
self.availableTags = [
"ActionScript", "AppleScript", "Asp", "BASIC", "C",
"C++", "Clojure", "COBOL", "ColdFusion", "Erlang",
"Fortran", "Groovy", "Haskell", "Java", "JavaScript",
"Lisp",
"Perl", "PHP", "Python", "Ruby", "Scala",
"Scheme"
self.matchedTags = ko.observableArray([]);
self.tag = ko.observable().extend({
rateLimit: {
timeout: 1000,
method: "notifyWhenChangesStop"
}
});
self.tag.subscribe(function(value) {
self.matchedTags.removeAll();
En el ejemplo anterior, se crean dos matrices. Una de ellas contiene la lista de etiquetas de
buscar. El otro es un observableArray que será actualizado y contiene etiquetas que coincidir con
lo que el usuario escribe.
Una tags observable también se crea y se extiende con un Ratelimit de un segundo después de que
deja de cambiar. Esta propiedad está suscrita a continuación. Cuando cambia la propieda (después
del retardo), esta función se llama. Despeja las matchedTags matriz y bucles a través de la lista de
etiquetas y añade ningún partido a la matriz.
Si ejecuta este ejemplo y escribe una en el cuadro de texto que está obligado-datos al retraso
propiedad observada, después de un segundo de la lista de etiquetas coincidentes se rellenará con
varios partidos. No es tan bonito como autocompletar de jQuery, pero me gusta el mejor limitación
de velocidad que ¡proporciona!
Knockout no incluye ninguna función para llevar a cabo la interacción del lado del servidor. Es
completamente de usted. Puede usar jQuery, vainilla JavaScript o cualquier otra biblioteca que tu
prefiere.
Sugiero usar jQuery porque algunos de los ejemplos anteriores ya se están utilizando, que significa
que es muy probable que ya incluye en su proyecto, lo que añade sin adiciones override cional.
Envío de datos
Cuando se trata de enviar datos, que suelen utilizar unos formatos diferentes dependiendo de si
estoy interactuando con una API REST o si estoy POSTeando un formulario estándar. Ahí dos
grandes diferencias cuando se cambia entre los tipos:
2. El contenido de la forma es también diferente. Cuando se realiza una forma estándar POST,
los datos se serializado como un par JavaScript clave / valor estándar de datos.
Considerando que, al interactuar con un API REST JSON, los datos del formulario serían
SERIAS alized a JSON. Knockout proporciona funciones útiles para desenvolver
observables y convertirlos a los tipos necesarios que serán exploradas en la próxima
Ejemplos.
En el Ejemplo 8-1 , voy a crear una forma estándar que aprovecha varios Knockout
binding. Cuando se envía el formulario, que se llevará a cabo a través de AJAX con el modelo
normalizado ENVIAR.
55
Ejemplo 8-1. POST de formulario a través de AJAX
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
<form data-bind="submit: validateAndSave, with: person">
<input type="text" data-bind="value: firstName"
placeholder="Enter your first name" required /><br/>
<input type="text" data-bind="value: lastName" placeholder="Enter
your last name" required /><br/>
<input type="email" data-bind="value: email"
placeholder="Enter your email" required /><br/>
<input type="submit" />
</form>
self.person = {
firstName: ko.observable(), lastName:
ko.observable(), email: ko.observable()
};
self.validateAndSave = function(form) {
if (!$(form).validate()) return;
$.ajax({
url: 'myform.aspx',
data: ko.toJS(self.person), type: 'POST',
contentType: 'application/x-www-form-urlencoded'
}).success(self.successSave).error(self.errorSave);
};
self.successSave = function() {
alert('Success!');
};
self.errorSave = function() {
alert('Error!');
};
};
Este ejemplo es bastante similar al ejemplo mostrado en el Capítulo 5 . Unos pocos cambios clave
ha sido hecho. En primer lugar, los elementos observables anteriores para los campos han sido
convierte en un objeto person . Esto se hace para que sea más fácil de someter la totalidad del
objeto a través de AJAX. Esto se puede ver el interior de la validateAndSave función donde los
datos siendo suministrado a través de AJAX se Uso de la función Knockout ko.toJS para convertir
los person de un objeto en JavaScript par clave / valor utilizable.
Si la llamada AJAX tiene éxito, el successSave se ejecutará la función, que se mostrar un mensaje
de éxito en un diálogo de alerta. Del mismo modo, si se produce un error, el error Guardar función
será llamada, y se muestra un mensaje de error.
Ejecutar el Ejemplo
El resultado más probable de ejecutar el ejemplo anterior hará que el diálogo de error que aparezca
ya que la forma está intentando enviar a una página llamada myform.aspx, que no existe.
Los únicos otros cambios significativos en el ejemplo anterior son los form datos de la etiqueta
Enlaces. Anteriormente, se une a un Validar función; ahora se une a una validateAndSave función
(un nombre un poco más detallado). También aprovecha la with binding a la objeto person de
evitar prefijar cada elemento de entrada a ese objeto.
$.ajax({
url: 'myform.aspx',
data: ko.toJSON(self.person), type: 'POST',
contentType: 'application/json'
})
En lugar de utilizar el ko.toJS función, que es sustituido por el muy similar ko.toJSON
función. Como su nombre lo indica la función, esto convierte la persona objeto en un JSON
representación de la misma. El otro cambio es menor que contentType se establece ahora
en application / json.
Envío de datos | 57
ko.toJS y ko.toJSON
Los ko.toJS y ko.toJSON funciones de forma recursiva pasan por el todo objeto y desenvolver
propiedades o matrices de ser una propiedad observada a una propiedad común de JavaScript.
Recepción de datos es bastante similar al envío de datos, pero a la inversa. Cuando va a enviar
datos a un servidor, que suelen utilizar los observables para capturar y enviar datos. cuando
recibiendo ción de datos, es muy habitual el uso de propiedades o características observables para
almacenar la respuesta de un servidor.
Para demostrar esto, Ejemplo 8-3 convertirá el ejemplo autocompletar creado en Capítulo 7 . Esta
vez, el availableTags matriz no se incluirá directamente en el modelo de vista; los datos serán
cargados a través del servidor.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
Tags Matching:
<ul>
<!-- ko foreach: matchedTags -->
<li data-bind="text: $data"></li>
<!-- /ko -->
</ul>
self.matchedTags = ko.observableArray([]);
self.availableTags = [];
self.tag = ko.observable().extend({
rateLimit: {
timeout: 1000,
method: "notifyWhenChangesStop"
}
self.tag.subscribe(function(value) {
self.matchedTags.removeAll();
$.ajax({
url: 'tags.html', type: 'GET',
contentType: 'application/json', dataType:
'json'
}).success(function(data) {
self.availableTags = data;
});
};
Este ejemplo es casi idéntica a la del ejemplo anterior con la excepción de que la availableTags se
rellena con la respuesta de la llamada AJAX recién agregado.
La solicitud llamadas AJAX tags.html (mostrado en el Ejemplo 8-4 ), Que contiene la misma lista
de etiquetas del ejemplo anterior. Debido a que la llamada AJAX se le dijo la respuesta sería JSON,
la matriz de palabras se puede almacenar directamente en el availableTags matriz.
[
"ActionScript", "AppleScript", "Asp", "BASIC", "C",
"C++", "Clojure", "COBOL", "ColdFusion", "Erlang",
"Fortran", "Groovy", "Haskell", "Java", "JavaScript",
"Lisp",
"Perl", "PHP", "Python", "Ruby", "Scala",
"Scheme"
]
Si el servidor contiene un lenguaje que tiene acceso a la base de datos, esto sería una perfecta
ejemplo para implementar ir a buscar la lista de etiquetas de un archivo no estático.
Recepción de datos | 59
Pueden requerir a un servidor Web
El ejemplo anterior podría requerir un servidor web para ejecutar. Si tu fueron previamente en
marcha los ejemplos como archivos HTML (por ejemplo, la dirección URL era file: // ), es
posible que reciba un error al realizar la AJAX solicitud.
Para fines de desarrollo, recomiendo la creación de XAMPP servidor , que es compatible con
Windows, Linux y Mac OS X. Una vez instalado, los archivos de ejemplo se pueden colocar
dentro de la htdocs directorio donde está instalado XAMPP.
Un ejemplo de este tipo podría ser alterado fácilmente para mover el juego de etiquetas para la
servidor y tomar los resultados y el establecimiento de la matchedTags gama observable desde el
respuesta.
Ejemplo 8-5 demostrará parcialmente este pretendiendo la respuesta a la AJAX solicitud contiene
sólo las etiquetas que responden a nuestra consulta.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
Tags Matching:
<ul>
<!-- ko foreach: matchedTags -->
<li data-bind="text: $data"></li>
<!-- /ko -->
</ul>
self.matchedTags = ko.observableArray([]);
self.tag = ko.observable().extend({
self.tag.subscribe(function(value){
self.matchedTags.removeAll();
if (value !== '') {
$.ajax({
url: 'tags.html',
type: 'GET',
contentType: 'application/json',
dataType: 'json'
}).success(function(data) {
self.matchedTags(data);
});
}
});
};
El ejemplo anterior ya no contiene los availableTags y el bucle para realizar el partido; en cambio,
cualesquiera que sean los resultados son de la petición AJAX son directamente asignado a
la matchedTags matriz observable.
Recepción de datos | 61
CAPÍTULO 9
El Mapeo Plugin
Esto puede ser extremadamente útil en varias situaciones diferentes. Donde habíamos estado
creando objetos y definir manualmente cada propiedad como observables, el plug-in de mapeo lo
hará automáticamente.
Mapa de un objeto
En el Ejemplo 9-1 , convierto un ejemplo de Capítulo 3 que demuestra la con la unión en un
solo libro objeto. En el ejemplo original, un book objeto se pasa a la viewModel a través del
constructor. Esto entonces se asigna directamente al interior del libro propiedad y se utiliza para
mostrar con fijaciones Knockout. Sin embargo, debido a que es utilizando el plugin mapeo, todas
las propiedades (title , synopsis , y publishedDate ) que se están observando ahora.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
63
<body>
self.book = ko.mapping.fromJS(book);
self.formatDate = function(dateToFormat) {
var months = new Array("January", "February", "March", "April", "May",
"June", "July", "August", "September", "October", "November", "December");
var book = {
title: 'Rapid Application Development With CakePHP', synopsis:
'...',
isbn: '1460954394', publishedDate: '2011-02-
17'
};
El otro cambio es la propiedad reserva ahora se está estableciendo con los ko.mapping.fromJS
función, que convierte cada propiedad en un observable.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
</table>
self.books = [
{
title: 'Rapid Application Development With CakePHP', isbn:
'1460954394',
publishedDate: '2011-02-17'
}, {
title: '20 Recipes for Programming MVC 3: Faster,
Smarter Web Development',
isbn: '1449309860', publishedDate: '2011-10-
14'
}, {
title: '20 Recipes for Programming PhoneGap:
Cross-Platform Mobile Development for Android and iPhone', isbn:
'1449319548',
publishedDate: '2012-04-06'
}
];
self.book;
self.hasFetchedBook = ko.observable(false);
self.loadBook = function() {
$.ajax({
url: 'book.html', type: 'GET',
contentType: 'application/json'
}).success(function(data) {
self.book = ko.mapping.fromJSON(data, self);
self.hasFetchedBook(true);
});
};
self.formatDate = function(dateToFormat) {
var months = new Array("January", "February", "March", "April", "May",
"June", "July", "August", "September", "October", "November", "December");
En este ejemplo, el título del libro dentro de la tabla es un enlace HTML que se está enlazado a
datos a la loadBook función de clic. Esta función realiza una AJAX solicitud a la book.html página
(que se muestra en el Ejemplo 9-3 ). Esta contiene datos similares a el libro codificado en el
ejemplo anterior. Esta función también se establece la observables hasFetchedBook a la
verdadera causa del HTML para rendir de forma dinámica y mostrar el libro, imagen y todos.
{
"title": "Rapid Application Development With CakePHP",
"synopsis": "...",
"isbn": "1460954394",
"publishedDate": "2011-02-17",
"image": "http://ecx.images-amazon.com/images/I/41JC54HEroL._AA160_.jpg"
}
Lo anterior es el objeto libro anterior se transformó en JSON válida para ser analizada por el Plugin
de mapeo.
Al igual que en el apartado anterior, otro gran uso de la cartografía de JSON sería rellenar
dinámicamente un formulario por ir a buscar los datos desde el servidor, utilizando el mapeo plugin
y, a continuación, de unión a la forma a estos elementos.
En el Ejemplo 9-4 , Vamos a juntar varias cosas diferentes que hemos discutido, pero todavía no
totalmente implementado. Este ejemplo demuestra datos de mapeo para un formulario, haciendo
solamente las propiedades necesarias observadas y utilizando funciones condicionales para trabajar
como una forma para añadir y editar.
<!DOCTYPE html>
<html>
<head>
<title>Data Binding with KnockoutJS</title>
</head>
<body>
var mapping = {
'observe': [ "firstName", "lastName", "email" ],
'ignore': [ "created" ]
};
if (self.user.id == 0)
alert("Creating a user");
else
alert("Updating a user");
};
};
var user = {
id: 1,
firstName: 'Mike', lastName:
'Wilson',
email: 'mike@notarealaddress.com', created: '2014-
10-12'
};
Este ejemplo acepta un usuario objeto en el constructor para el viewModel. Este objeto a
continuación, se asigna a un interior de usuario propiedad que está unido a los elementos de
formulario para edición.
El usuario objeto contiene varias propiedades adicionales que pueden ser útiles, pero no
editable dentro de la forma. Para no hacer que estos objetos observados innecesariamente, varios
las opciones de asignación se definen y se pasan a la función de mapeo.
En primer lugar, una lista explícita de propiedades que requieren atención se define en el observar
opción. Estas propiedades se ajustan a los elementos que están contenidos dentro de la
forma. Segundo, el ignorar la opción no se utiliza para mapear la creada propiedad, ya que no es
requerida en la página.
Para este capítulo final, pensé que sería una buena idea para ver varias de las cosas que se han
demostrado en pequeños ejemplos a lo largo de los capítulos anteriores. ¿Qué mejor manera de
hacerlo que con un carrito de la compra?
En los ejemplos anteriores, el código HTML y JavaScript a menudo se han presentado en una
ejemplo único. Debido a que este código HTML y JavaScript es un poco más grande que los
anteriores ejemplos, se ha dividido en varios pequeños archivos JavaScript y un archivo HTML.
Creo que cubre las principales características de un típico carrito de compras. Al observar estas
características, veo una necesidad inmediata de tres matrices:
Además de estas tres matrices, queremos hacer un seguimiento de la ejecución total actual.
Ejemplo 10-1 muestra el código HTML que cubre las particularidades del carrito de la compra.
71
Ejemplo 10-1. HTML para carrito de la compra
<!DOCTYPE html>
<html>
<head>
<title>Yet Another Shopping Cart</title>
</head>
<body>
<ul>
<!-- ko foreach: categories -->
<li><a href="#" data-bind=
"click: $parent.showProducts, text: name"></a></li>
<!-- /ko -->
</ul>
<ul>
<!-- ko foreach: availableProducts -->
<li>
<!-- ko template: { name: 'item-template', data: $data } -->
<!-- /ko -->
<p><button data-bind="click: $parent.addItem">Add to cart</button></p>
</li>
<!-- /ko -->
</ul>
</div>
<div style="float: left; width: 50%">
<ul>
<!-- ko foreach:
{ data: cartItems, afterAdd: fadeIn, beforeRemove: fadeOut } -->
<li>
<!-- ko template: { name: 'item-template', data: $data } -->
<!-- /ko -->
<p><button data-bind="click: $parent.removeItem">Remove</button>
</p>
</li>
<!-- /ko -->
</ul>
</div>
El uso de CSS en línea, la salida se divide en dos lados iguales. En el lado izquierdo, una lista de
categorías se muestra en una lista desordenada. Debajo de esta lista es una segunda lista
desordenada que muestra una lista de productos disponibles después de una categoría ha sido
seleccionada. Por defecto, la availableProducts matriz observable está vacía. Esta matriz se rellena
cuando una categoría se selecciona en el showProducts función que está enlazada a datos o al clic
evento.
En el lado derecho de la pantalla, los elementos de la compra se muestran en otra lista desordenada.
Usted puede notar que este foreach es diferente a los demás porque es el uso de la
afterAdd y beforeRemove funciones de devolución de llamada.
Debido a que la salida de los productos disponibles y artículos carrito seleccionados es lo mismo,
una plantilla ha sido creada para commonize la visualización del elemento. La unica diferencia
entre ellos se encuentra el botón que aparece debajo de cada elemento. Al mostrar disponibles
productos, el botón permite al usuario añadir un artículo y cuando indicación del valor
seleccionado cesta productos, el botón permite al usuario retirar el artículo.
También en el lado derecho, se muestra el número total de productos añadidos a la cesta, como se
así como la compra coste total acumulado.
Por último, hay varios archivos JavaScript que se incluyen en la parte inferior del HTML. Una
nueva biblioteca ( jQueryUI ) Se ha agregado a realizar las animaciones sencillas cuando se añaden
o eliminan de la cesta de la compra artículos. Los archivos de otro tipo ( classes.js , data.js ,
viewmodel.js ) son los archivos divididos para centrarse mejor en cada archivo a su vez. Ver
Ejemplos 10-2 , 10-3 Y 10-4 .
function ViewModel(categories) {
var self = this;
self.categories = categories;
self.cartItems = ko.observableArray([]);
self.cartTotal = ko.computed(function() {
var total = 0;
for (var i = 0; i < self.cartItems().length; i++)
total += self.cartItems()[i].price;
return total;
});
self.showProducts = function(category) {
self.availableProducts(category.items);
};
self.addItem = function(item) {
self.cartItems.push(item);
};
self.removeItem = function(item) {
self.cartItems.remove(item);
};
self.fadeIn = function(element) {
$(element).hide().fadeIn('slow');
};
self.fadeOut = function(element) {
$(element).slideUp(function() {
$(element).remove();
});
};
};
Las categorías que se pasan al constructor serán mostradas en el Ejemplo 10-3 cuando el data.js se
visualiza archivo. El array se almacena en el array de categorías interno.
Los availableProducts y cartItems, se definen como matrices observables vacías que se utilizará
para mostrar dinámicamente los productos de una categoría y lo dado artículos en la compra del
usuario, respectivamente.
var categories = [
new Category(1, "Books", [
new Book("1", "Book 1", "Book 1 Description", 1.99), new
Book("2", "Book 2", "Book 2 Description", 2.99), new Book("3",
"Book 3", "Book 3 Description", 3.99)
]),
new Category(2, "Movies", [
new Movie("Movie 1", "Movie 1 Description", 120, 4.99), new
Movie("Movie 2", "Movie 2 Description", 160, 5.99), new Movie("Movie
3", "Movie 3 Description", 110, 6.99)
]),
new Category(3, "Music", [
new Album("Artist 1", "Album 1", 10, 4.99), new
Album("Artist 2", "Album 2", 8, 7.99), new Album("Artist
3", "Album 3", 12, 6.99)
])
];
Tres categorías diferentes se crean: Libros, películas y música. Cada elemento de la categoría y la
propia categoría se crean mediante la creación de nuevos objetos (Category, book , Movie ,
y Album ). Estos se muestran con el classes.js archivo en el Ejemplo 10-4 .
self.getTitle = function() {
return self.title;
};
self.getDescription = function() {
return self.description;
};
self.getTitle = function() {
return self.title;
};
self.getDescription = function() {
return 'Summary: ' + self.description + '<br/>' +
'Movie length: ' + self.movie_length;
};
};
self.artist = artist;
self.name = name;
self.number_of_songs = number_of_songs;
self.price = price;
self.getTitle = function() {
return self.name;
};
self.getDescription = function() {
return 'Artist: ' + self.artist + '<br/>' +
'Number of songs: ' + self.number_of_songs;
};
};
La categoría de objeto acepta tres parámetros: id, name , y una variedad de artículos . Estas son los
elementos que se utilizan para rellenar los availableProducts gama observable cuando se selecciona
una categoría.
El restante objetos- libro , Movie y álbum -son ligeramente diferente en lo que respecta a lo que los
datos que aceptan como parámetros. Esto permite que los datos se estructuran diferente en función
del tipo de producto que es; Sin embargo, cada objeto tiene tres compartían
propiedades: price, getTitle y getDescription . Dentro de cada objeto, el getTitle
y getDescription funciones se utilizan para determinar la forma en la salida debe ser formateado
cuando se muestra el artículo. Esto simplifica el código HTML original para evitar procesamiento
condicional cuando se muestra un elemento.
Lo dejo a usted para construir la forma final (enlaces de datos y todo) para recoger el usuario de el
contacto y la información de tarjeta de crédito para terminar la comprobación de su carrito de la
compra!
La simplicidad de Knockout
El último capítulo significó la conclusión de los ejemplos de código de este libro. Mientras yo
estaba trabajando en el plan para este libro, pensé que el último capítulo contendría un significante
de cantidad de más de código. Un carro de compras no es una cosa fácil de construir, ya que
incluye muchos componentes, tales como categorías de navegación, productos y artículos de
seguimiento el usuario añade a su carrito de compras. Realmente espero que esto demuestre cómo
KnockoutJS encaja en sus proyectos y hace que el mantenimiento de un estado a través de una
única página web realmente fácil. El modelo de vista final para el carrito de la compra fue de
menos de 40 líneas de código (Incluyendo saltos de línea para facilitar la lectura)! El HTML que
realiza los datos necesarios encuadernaciones era también menos de 40 líneas de código! La forma
Knockout trae esto juntos las interacciones del usuario con simples hace que las personas de 80
líneas de código muy potente.
El enfoque de este libro fue sobre el aprendizaje de los entresijos de la eliminatoria. Creo que cada
característica estaba cubierta. Si tuviera que avanzar en el ejemplo carrito de la compra, me
concentro en el diseño. La implementación actual parece bastante simple, pero con un poco de
estilo, que llevaría rápidamente en un aspecto totalmente nuevo con poco o ningún cambio en el
JavaScript. Por supuesto, el diseño no es mi fuerte, así que lo dejo a los diseñadores!
Antes de utilizar Knockout, he construido interfaces de usuario del lado del cliente pesadas, y yo
puedo asegurar que participa significativamente más de 80 líneas de código. Se jQuery compleja
involucrada añadir y quitar de forma dinámica los elementos HTML, o agregar y quitar CSS
Clases Compare esto con Knockout, donde se tarda unos pocos caracteres de enlaces de datos a
lograr la misma cosa!
79
Contexto del usuario
Tanto como usuario de Internet y un desarrollador web, estoy constantemente pensando en
usabilidad y las interfaces de usuario. Uno de los ejes principales presto mucha atención es el
usuario de contexto.
Por ejemplo, es bastante común para datos adicionales para ser cargadas a través de AJAX. Veo
dos enfoques comunes para este: Carga de los datos y la adición por debajo de la existente
contenga, o carga de los datos y reemplazar el contenido existente. El ex perfectamente mantiene
mi contexto. En este último ejemplo, cuando se sustituye el contenido, que es extremadamente
importante que, como usuario, mi contexto es de esperar de nuevo al comienzo de la nuevos
contenidos y no en la parte inferior de los nuevos contenidos en la acción para cargar el El
contenido era.
Otro ejemplo común es con una forma. Estos son sometidos a menudo a través de AJAX (como se
se muestra en este libro). Cuando se muestra un error, es importante pensar en donde se muestra
este mensaje. Probable contexto del usuario sería la parte inferior del formulario donde el botón de
envío es. Si se muestra un error en la parte superior de la pantalla, probablemente pasará
desapercibido por el usuario.
Al crear aplicaciones dinámicas del lado del cliente, Knockout hace que sea muy fácil de mantener
cualquier contenido en la pantalla hacia arriba al día, que implica especialmente la interacción del
usuario. Aunque Knockout hace que sea fácil, es importante que el contexto se mantenga
correctamente. Más a menudo, no se requiere ningún esfuerzo, pero asegúrese de tener esto en
cuenta cuando se altera gran porciones de los contenidos. Esto hará que la pantalla para cambiar el
tamaño, lo que podría perder el contexto apropiado.
Tenía una gran discusión acerca de esto el otro día con un compañero de trabajo. Tuvimos la
opción a:
Que no quieren perder el contexto del usuario, se eligió la segunda opción. Claro, se tomó 2
minutos para escribir el bucle y la sentencia condicional en comparación con 15 segundos para
escribir location.reload. Sin embargo, el resultado de la elección de la opción dos es un usuario
mucho mejor experimento La Al hacer clic en el botón hace que la interfaz de usuario para
actualizar, proporcionando (casi) retroalimentación instantánea después de la acción tiene lugar.
Conclusión
Espero que este libro le haya proporcionado una gran cantidad de ejemplos útiles. Mientras
pensaba cada característica, he tratado de pensar en cómo lo uso a diario en mis proyectos. Y donde
he podido, he pasado en las pequeñas complejidades que he tropezamos mientras utilizando
Knockout dentro de un gran proyecto.
Conclusión | 81
Índice
Symbols
$data variable, 11
$index variable, 12
$parent variable, 11, 15
$parents variable, 11, 15
$root variable, 11, 15
A
afterAdd method, 15 afterMove method, 15 afterRender method, 15
AJAX, 55, 80
alert statements, 22 arrays
in shopping cart example, 71 observable arrays, 22 selectedOptions binding and, 31
B
beforeMove method, 15 beforeRemove method, 15 brackets, 28
C
callback methods, 15-17
CamelCase, 8 checked binding, 31 click binding, 33
computed observables, 22 conditional statements, 9, 28, 68
CSS
classes, binding of, 8 display property, 24
display: none style, 26 custom data bindings, 40 custom functions, 47
D
data
receiving, 58-61 sending, 55-58
data binding
adding multiple, 8 condition-based, 9, 28 creating custom, 40
CSS classes and styles, 8
HTML attributes, 8
HTML data, 7
specifying with HTML comments, 1 syntax for, 1
two-way, 31
data binding context foreach bindings, 12-15
foreach callbacks (events), 15-17 navigating between, 11 parent/child hierarchy, 11
root context, 11
with bindings, 17-19 data validation, 36
data-bind attribute, 1, 7 disable binding, 31 display property, 24
DOM (Document Object Model), 27, 33 drop-down lists, 31, 34
E
elements
83
adding/removing, 26 form elements, 31-38 showing/hiding, 24
enable binding, 31 event binding, 33 events
foreach callbacks, 15-17 used with forms, 33
F
foreach bindings, 12-15
foreach callbacks (events), 15-17 form elements, 33
forms
adding to/editing, 68
bindings for form elements, 31 enabling/disabling text boxes, 31 event data bindings, 33
form validation, 36 listening for changes, 34 sending data from, 55-58 two-way bindings for, 31 working with, 31-38
functions
adding custom to observables, 49 conditional, 68
creating custom, 47
H
hasFocus binding, 33
HTML
binding attributes, 8 binding HTML data, 7
data bindings via comments, 1 data-bind attribute, 1
displaying lists in HTML tables, 13 for shopping cart example, 71 repeating sections on arrays, 12 reusing templates, 43
I
if/ifnot data bindings, 26 inheritance, 49
input element, 31, 33
J
JavaScript, 4, 43, 63 jQuery, 17, 55
jQuery Validation Plugin, 36
K
key/value pairs, 55 keypress event, 33
KnockoutJS
basic implementation
data binding example, 2 data binding syntax, 1
MVVM (Model-View-ViewModel), 3 overview of, 1
ViewModel creation, 3
ViewModel object orientation, 4
ViewModels with parameters, 5 benefits of, vii, 1
common uses of, 2 history of, vii installing, vii plugins for, 63 purpose of, 1 templates, 43
version changes, viii ko.applyBindings function, 3, 11, 14, 39 ko.mapping.fromJS, 64 ko.mapping.fromJSON function, 67
ko.observable function, 21
ko.toJS function, 57 ko.toJSON function, 57
L
listening mode, 23 lists, 31
M
mapping plugin
map from an object, 63 map from JSON, 65 purpose of, 63
Model-View-Controller (MVC) pattern, 3
Model-View-ViewModel (MVVM) pattern, 3 mouseover event, 33
Mozilla Developer Network (MDN), 4 multiselect lists, 31
O
object-oriented programming (OOP), 4 observables
accessing, 22
84 | Index
adding custom functions to, 49 adding/removing elements, 26 best use of, 28, 68
combining into single object, 22 computed observables, 22 creating observable variables, 21 defining, 21
extending with custom functions, 47 instantiating observable arrays, 22 partial application of, 28 pureComputed
observables, 23 purpose of, 21
rate-limiting, 51-53 selectedOptions binding and, 31 showing/hiding elements, 24 storing server responses with, 58
subscribe function, 34
updates with textInput vs. value bindings,
31
use of brackets and, 28 visible data binding, 24
onChange events, 32 options binding, 31
P
parent/child hierarchy, 11 parentheses, 43
plugins, 63
(see also mapping plugin) POST request method, 55 properties
dynamically changing, 21 (see also observables)
observing/ignoring specific, 68 storing server responses with, 58
pureComputed observables, 23
R
rate-limiting observables, 51-53
REST APIs, 55
S
screen flickers, preventing, 26 select element, 31 selectedOptions binding, 31 self variable, 5
server-side interaction choices for, 55
mapping from, 65 receiving data, 58-61 sending data, 55-58
shopping cart example addItem, 74
animated enhancements for, 81 arrays needed, 71 availableProducts, 74
benefits of KnockoutJS for, 79 cartItems, 74
cartTotal, 74
core features of, 71 current running total, 71 design improvements, 79 fadeIn/fadeOut functions, 75
HTML for, 71 output, 73 removeItem, 74 showProducts, 74
showExtraData variable, 26, 28 sleeping mode, 23
style bindings, 8 submit binding, 33 submit data binding, 36 subscribe function, 34
T
templates, 43, 73
text boxes, enabling/disabling, 31 textarea element, 31, 40
textInput binding, 31 this variable, 5
TinyMCE WYSIWYG editor, 40 two-way bindings, 31
U
unobtrusive form validation, 36 updateObservable function, 25 user interfaces (UIs)
animated enhancements for, 81 content updates, 80
dynamic, vii
role of KnockoutJS, 1 user's context, 80
V
validate function, 37 validation, of forms, 36
Index | 85
W
with bindings, 17-19
WYSIWYG editors, 40
X
XAMPP server, 60
86 | Índice
Sobre el Autor
El autor de 20 recetas para la programación MVC 3 y 20 Recetas para la
ProgramaciónPhoneGap de O'Reilly Media, Jamie Munro ha sido el desarrollo de sitios
web y web las solicitudes de más de 15 años. Durante los últimos 8 años, Jamie ha estado
actuando como una ventaja desarrollador de tutoría a los desarrolladores más jóvenes para
mejorar sus habilidades de desarrollo web.
Tomando su amor por la tutoría gente, Jamie empezó su carrera de escritor en su personal
un blog en 2009. Como el blog de Jamie creció en el éxito, se volvió a su pasión por escrito
libros sobre el desarrollo web con la esperanza de que sus muchos años de experiencia
podría ser pasó a usted, el lector.
Colofón
El animal en la portada de Knockout.js es un canguro de árbol negro ( Dendrolagus
ursinus ), un marsupial que habita en las selvas tropicales de Nueva Guinea, lejos
Northeastern Queensland, y algunas de las islas de la región. El canguro del árbol es el
único verdadero miembro arbórea de la familia de los canguros.
El canguro del árbol negro se reconoce fácilmente por sus largas orejas peludas, que son
únicos entre las especies de árboles canguro. Pelo largo y negro cubre la parte posterior y la
cola, mientras que la piel en la parte inferior es de color café. Su cara es más distintivo de
color marrón, con blanco o a veces las mejillas rojas y una garganta blanca.
El canguro del árbol negro es conocido por ser en su mayoría solitarios y nocturnos,
emergiendo después oscuro para alimentarse de su alimento preferido de las hojas y los
frutos.
los pueblos indígenas en todo el rango del canguro arborícola cazan los animales para la
alimentación, a veces el uso de perros para rastrearlos. Para varias especies, la caza por sí
solo tiene impulsado estos marsupiales cerca de la extinción.
Muchos de los animales en peligro de extinción cubiertas O'Reilly están; todos ellos son
importantes para el mundo. Para obtener más información sobre cómo puede ayudar, ir
a animals.oreilly.com .