Sie sind auf Seite 1von 62

Para trabajar con ExtJS:

1. Servidor Web (XAMPP o WAMP - Apache)


2. IDE para escribir código JavaScript (JetBrains WebStorm, Secha Architect, Aptana, Eclipse,
VisualStudio etc.)
3. Librería (SDK ExtJS)

BASICO

Definir nueva clase:


Use el método Ext.define () para definir una nueva clase personalizada en Ext JS 4, 5 y 6.

Sintaxis:
Ext.define((String) className, (Object) classMembers, (Optional Function) onClassCreatedCallback);

Parámetros:
className: es el nombre completo de la clase en formato punto-nombre de la ubicación/proyecto.

classMembers: es un objeto que representa una colección clases miembro en pares clave-valor (literales de
objeto Javascript).
onClassCreatedCallback: es una función opcional de llamada que se invoca cuando todas las dependencias
de esta clase están listas y la clase en sí está totalmente creada.

Ext.define() realiza las siguientes operaciones:

1. Detecta y crea nuevos namespaces si es necesario.


2. Extiende una clase existente.
3. Verifica si la clase que se está extendiendo se ha definido, de lo contrario, aplazará la creación de la
nueva clase hasta que la clase utilizada para la extensión esté disponible.
4. Devuelve el objeto Ext.Base.

Nota: Ext.Base es la raíz de todas las clases creadas con Ext.define. Todas las clases en Ext JS heredan de
Ext.Base.

Ext.define('Student',
{
name: 'unnamed',
getName: function(){
return "El nombre del Estudiante es:" + this.name;
}
}, function(){
alert('Objeto Student se creó');
});

El ejemplo anterior define la clase Student con una variable miembro 'name' y un método getName ().

Según la sintaxis de Ext.define, el primer parámetro 'Student' es el nombre de la clase. El segundo parámetro
es un objeto de JavaScript que contiene el name y getName (), y el tercer parámetro (opcional) es la función o
método que se llamará después de crear la clase "Student".
De esta manera se puede crear una clase personalizada en Ext JS.

Crear un objeto de una clase:


JavaScript nos permite crear un objeto usando una nueva palabra clave. Sin embargo, Sencha recomienda usar
el método Ext.create () para crear un objeto de una clase que se crea usando el método Ext.define ().

El siguiente ejemplo muestra cómo crear un objeto de la clase Student y llamar al método getName ().

var studentObj = Ext.create('Student');


studentObj.getName();

Definir Constructor:
Para definir una clase personalizada con el constructor, agregue el constructor del nombre de la función como un
miembro de la clase:
Ext.define('Student', {
name: 'unnamed',
getName: function(){
return 'El nombre del Estudiante es ' + this.name;
},
constructor: function(studentName){
if(studentName)
this.name = studentName;
}
});

Ahora puedes crear un objeto pasando un parámetro al constructor:

var studentObj = Ext.create('Student','XYZ');


//or
var studentObj = new Student('XYZ');
studentObj.getName();
//salida: El nombre del Estudiante es XYZ

Declarar miembros privados en una clase:


Use el cierre de JavaScript para crear miembros privados de la clase como se muestra a continuación:
Ext.define('Student', function(){
var name = 'unnamed';

return {
constructor: function(name){
this.name = name;
},
getName: function(){
alert('El nombre del Estudiante es ' + this.name);
}
};
});

//crea un objeto de la clase Student


var studentObj = Ext.create('Student','XYZ');
studentObj.getName();

No puede acceder la propiedad name directamente, ya que es un miembro privado. Use el método getName
() en el objeto student para acceder al name.

Declarar miembros estáticos en clase:


Se puede acceder a los miembros estáticos en una clase Ext JS sin crear un objeto usando el método
Ext.create (). Se puede acceder usando el nombre de la clase con notación de puntos igual que otros
lenguajes de programación.

Declare miembros estáticos en la clase Ext JS usando el parámetro 'statics' como se muestra a continuación.

Ext.define('Student',
{
name: 'unnamed',
getName: function(){
alert('Student name is ' + this.name);
},
constructor: function(studentName){
if(studentName)
this.name = studentName;
},

statics:
{
getSchoolName: function(){
return "XYZ";
}
}
});

//llamada al metodo estatico


alert(Student.getSchoolName());

Como puede ver en el ejemplo anterior, la función getSchoolName () se define dentro del objeto de
parámetro estático. Así que ahora puedes llamarlo como Student.getSchoolName ().

Herencia en Ext JS:


Ext JS admite conceptos de programación orientados a objetos como clase, herencia, polimorfismo, etc.
Podemos heredar una nueva clase de la clase existente utilizando la palabra clave extend al definir una nueva
clase en Ext JS.
Por ejemplo, defina una clase Person con el método getName como se muestra a continuación.
Ext.define('Person',
{
name: 'Unknown',

constructor: function(name){
if(name){
this.name = name;
}
},

getName: function(){
alert("My name is " + this.name);
}
});

Ahora, defina la clase de Student con extend: 'Person' en la sección de configuración como se muestra a
continuación.

Ext.define('Student',
{
extend: 'Person',
schoolName: 'Unknown',

constructor: function(name, schoolName){


this.schoolName = schoolName || 'Unknown';

//llamada a clase constructor padre


this.callParent(arguments);
},

getSchoolName: function(){
alert("El nombre de mi Escuela es " + this.schoolName);
}
});

var newStudent = new Student('XYZ', 'ABC School');


newStudent.getName(); //salida: XYZ
newStudent.getSchoolName(); //salida: ABC School

Como puede ver arriba, la clase Student hereda la clase Person usando la palabra clave de extend. Así que
ahora, podemos llamar al método getName () en el objeto Student, que a su vez llamará al método getName
() de la clase Person.
Nota: la mayoría de las veces tendrá que extender los componentes Ext JS en su aplicación para usar la
funcionalidad predeterminada del componente y agregar una funcionalidad personalizada.

Mixins:
Mixins fue introducido desde Ext JS 4. Mixins nos permite usar funciones de una clase como una función de
otra clase sin herencia.
Los mixins se pueden definir utilizando la palabra clave mixins y especificando el valor como un objeto JSON
donde el nombre de una propiedad debe ser el nombre del método que desea usar y el valor de una
propiedad será el nombre de la clase donde se define el método.

Considere el siguiente ejemplo.

Ext.define('Person', {
name: 'Unknown',

constructor: function(name) {
if (name) {
this.name = name;
}
},

getName: function() {
alert("Mi nombre es " + this.name);
},

eat: function(foodType) {
alert("Estoy comiendo " + foodType);
}

});

Ext.define('Student', {
schoolName: '',

constructor: function(schoolName) {
this.schoolName = schoolName || 'Unknown'
},

mixins: {
eat: 'Person'
},

getSchoolName: function() {
alert("Soy un estudiante de " + this.schoolName);
}

});

var studentObj = new Ext.create('Student', 'XYZ');


studentObj.eat('Sandwich');

En el ejemplo anterior, la clase Student define los mixins y especifica 'eat' como nombre de propiedad y
'Person' como valor donde se define el método eat (). Así que ahora puede llamar al método studentObj.eat
() como si estuviera definido en la clase Student.

Config:
Ext JS tiene una característica llamada Config. Config permite declarar propiedades públicas con valores
predeterminados que serán completamente encapsulados desde otros miembros de la clase. Las
propiedades que se declaran a través de Config, tendrán los métodos get () y set () automáticamente si la
clase no tiene estos métodos ya definidos.
Las propiedades en Config se pueden definir utilizando la palabra clave config con el objeto JSON como un
valor donde puede definir propiedades. Considere el siguiente ejemplo.
Ext.define('Student', {
config:
{
name: 'unnamed',
schoolName: 'Unknown'
},
constructor: function(config){
this.initConfig(config);
}
});

En el ejemplo anterior, la clase de Student incluye dos propiedades Config: name y schoolName con el valor
predeterminado "undefined". En el constructor, llamamos this.initConfig (config). Esto creará métodos get y
set para todas las propiedades de config. Debemos llamar a this.initConfig (config) en el constructor para
inicializar getters y setters. El método get devuelve un valor de una propiedad config y el método set se usa
para asignar un nuevo valor a una propiedad config.
El nombre del método get empezará con get y el sufijo con el nombre de la propiedad como get <config
property name> () y de la misma manera, el método set se nombrará como set <config property name> (). El
sufijo en los nombres de método get y set empezará con letra capital. Por lo tanto, los nombres de método
get y set para el nombre anterior y las propiedades Config de schoolName serán getName (), setName (),
getSchoolName () y setSchoolName ().

El siguiente ejemplo muestra cómo acceder al método get y set de la clase de Student anterior.
Ext.define('Student', {
config:
{
name: 'unnamed',
schoolName: 'Unknown'
},
constructor: function(config){
this.initConfig(config);
}
});

var newStudent = Ext.create('Student', { name: 'XYZ', schoolName: 'ABC School' })


;

newStudent.getName();//salida: XYZ
newStudent.getSchoolName();//salida: ABC School

newStudent.setName('John');
newStudent.setSchoolName('New School');

newStudent.getName();//salida: John
newStudent.getSchoolName();//salida: New School

Como puede ver en el ejemplo anterior, no hemos definido los métodos getName (), setName () y
getSchoolName (), setSchoolName () en el objeto Student. Fue creado automáticamente para las propiedades
de config por Ext JS API.
Tenga en cuenta que no puede asignar el valor de la propiedad config directamente igual que la propiedad
de clase normal. Debe usar el método set para asignar un valor a la propiedad config. Por ejemplo, lo
siguiente NO es válido. No asigna un valor a la propiedad name, sino que crea otra propiedad name en la
instancia.

newStudent.name = 'Steve'; //invalido.


newStudent.setName('Steve');//Valido

Setters personalizados:
Usted ha visto que los métodos get y set se crean automáticamente para la propiedad config. Pero, cómo
agregar lógica adicional antes o después de que asignemos un valor a la propiedad config porque los métodos
get y set se administran internamente. La respuesta es setters personalizados (configuradores personalizados).
Los setters personalizados permiten agregar lógica adicional a sus setters. Hay dos setters personalizados:
apply y update.

El método apply () para la propiedad config nos permite agregar un poco de lógica adicional antes de asignar
el valor a la propiedad config. El nombre del método apply debe comenzar con apply mas el nombre de la
propiedad config como sufijo en CamelCase.
El método update () se ejecuta después de que se haya asignado el valor de la propiedad de configuración. El
nombre del método update debe comenzar con update mas el nombre de la propiedad config como sufijo en
CamelCase. Tiene dos parámetros, newValue y oldValue. Si incluye método apply y update para una
propiedad en particular, primero se aplicará apply y luego se llamará al método uppdate.
Considere el siguiente ejemplo.
Ext.define('Student',{
config:
{
name: 'unnamed',
schoolName : 'Unknown'
},

constructor: function(config){
this.initConfig(config);
},

applyName: function(name){
return Ext.String.capitalize(name);
},

updateName: function(newValue, oldValue){


alert('Nuevo valor: ' + newValue + ', Antiguo valor: ' + oldValue);
}
});

var newStudent = Ext.create('Estudiante', {name: 'xyz', schoolName: 'ABC School'}


);
newStudent.setName('john');

En el ejemplo anterior, hemos definido el método applyName () para la propiedad name en config que pondrá
en mayúsculas el valor de la propiedad name. Se llamará al método applyName () siempre que establezca el
valor de name en config usando el método setName (). Por lo tanto, puede asegurarse de que el valor del name
siempre estará en mayúsculas, incluso si el usuario lo configura en minúsculas.
El método updateName () en el ejemplo anterior se ejecuta después de asignar el valor de la propiedad config
y por eso incluye dos parámetros. El primer parámetro es para el nuevo valor y el segundo parámetro es para
el valor antiguo.

Eventos personalizados en Ext JS:


Ext JS nos permite definir eventos personalizados en clase utilizando Ext.mixin.Observable mixin.
Ext.mixin.Observable proporciona una interfaz común para publicar eventos en Ext JS 5 y 6.
El siguiente ejemplo muestra cómo puede publicar un evento utilizando mixins siempre que cambie el
nombre del alumno.

Ext.define('Student', {
config: {
name: ''
},
mixins:
{
observable: 'Ext.util.Observable'
},
constructor: function(config){
this.mixins.observable.constructor.call(this, config);
},
updateName: function(newValue, oldValue){
this.fireEvent('studentNameChanged', newValue);
}
});

var newStudent = Ext.create('Student', {name: 'xyz' });

newStudent.on('studentNameChanged', function(name){
alert('El nombre del estudiante ' + name + 'fue modificado.');
});
newStudent.setName('John');

En el ejemplo anterior, hemos incluido Ext.mixin.Observable mixin usando mixins config para que podamos
usarlo. En el constructor, llamamos this.mixins.observable.constructor.call (this, config) que inicializa la
configuración. En el método updateName (), activamos el evento personalizado StudentNameChanged
utilizando el método fireEvent () con un nuevo valor. Manejamos este evento en la instancia de newStudent
donde registramos el controlador usando el método on ().
Cada componente en Ext JS incluye la cantidad de eventos que podemos manejar en ViewController o en el
propio componente. Aprenda sobre el evento de componentes en la sección de componentes.

Trabajando con DOM:


Ext JS es una biblioteca DHTML. Crea la interfaz de usuario mediante la creación o manipulación de elementos
DOM utilizando JavaScript. Como puede saber, no todos los navegadores realizan la misma operación en
elementos DOM utilizando los mismos métodos de manipulación de JavaScript DOM. Hay problemas
relacionados con varios navegadores asociados con la creación y manipulación de DOM. Para resolver
problemas relacionados con varios navegadores, Ext JS incluye las siguientes clases para crear o manipular los
elementos DOM.

Ext.dom.Element
Ext JS incluye la clase Ext.dom.Element que envuelve el elemento HTML DOM real. La clase Ext.dom.Element
incluye métodos para modificar el elemento DOM y también gestiona los problemas en varios navegadores.
El método Ext.get () y Ext.fly () devuelve un objeto de Ext.dom.Element.

Method Description

Ext.get() Devuelve un objeto de Ext.dom.Element para el id específico del elemento DOM existente.

Ext.fly() Realiza la misma acción que Ext.get (). Está diseñado para manipular el elemento DOM como una sola
declaración y no almacena una referencia en memoria.

El siguiente ejemplo muestra cómo tomar una referencia de elementos DOM.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="../../ext-4.2.1/ext-4.2.1.883/ext-debug.js"></script>
<script>
Ext.onReady(function () {
// obtiene el objetp Ext.dom.Element
var txtFirst = Ext.get("txtFirstName");
txtFirst.set({ 'value': 'Steve' });

Ext.fly('txtLastName').set({ 'value': 'Jobs' });

console.log(txtFirst.$className);
});
</script>
</head>
<body>
Nombre: <input type="text" id="txtFirstName" class="myclass"/> <br /><br />
Apellido: <input type="text" id="txtLastName" class="myclass" />
</body>
</html>
En el ejemplo anterior, el método Ext.get () devuelve un objeto Ext.dom.Element para el tipo de entrada cuya
id es "txtFirstName". Luego puede usar varios métodos Ext.dom.Element para manipular el elemento DOM,
por ejemplo, el método set() se usa en el ejemplo anterior para establecer el valor de entrada. De la misma
manera, el método Ext.fly() se usa para obtener la referencia del elemento DOM y manipularlo en la misma
declaración.

Nota: cuando no necesita realizar varias operaciones en el elemento DOM, la función Ext.fly() es la forma
más eficiente de manipular un elemento DOM. Está diseñado para funcionar de manera más eficiente y
utiliza menos memoria.

En la siguiente sección, aprenda cómo crear o manipular elementos compuestos.

Elementos compuestos en Ext JS:


La clase de elementos compuestos Ext.dom.CompositeElement envuelve varias instancias Ext.dom.Element.
Incluye métodos que manipulan este grupo de instancias Ext.dom.Element en una sola llamada para que no
tengamos que obtener la referencia de cada Ext.dom.Element y realizar la misma operación para cada
elemento por separado.
Los elementos compuestos se pueden recuperar utilizando el método Ext.select(). El método Ext.select() toma
el selector de CSS como un parámetro de cadena y devuelve una instancia de Ext.dom.CompositeElement o
Ext.dom.CompositeElementLite.
Ext.select(selector, [unique], [root] )

El siguiente ejemplo muestra cómo manipular múltiples elementos DOM en una sola llamada de método.
<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="../../ext-4.2.1/ext-4.2.1.883/ext-debug.js"></script>
<script>
Ext.onReady(function () {
// Obtiene todos los elementos de entrada y configura su bgcolor a amarillo
var inputElements = Ext.select("input");

inputElements.set({'style': 'background-color:yellow'});
});
</script>
</head>
<body>
Nombre: <input type="text" id="txtFirstName" class="myclass"/> <br /><br />
Apellido: <input type="text" id="txtLastName" class="myclass" />
</body>
</html>

En el ejemplo anterior, Ext.select() devuelve Ext.dom.CompositeElement que incluye todos los elementos de
entrada. A continuación, puede manipular todos los elementos en una sola declaración. El método set()
establece el atributo de estilo de todos los elementos seleccionados.

De la misma manera, puede seleccionar otros elementos pasando diferentes selectores de CSS al método
select() y usar varios métodos Ext.dom.CompositeElement. Visite sencha docs para conocer todos los métodos
Ext.dom.CompositeElement.

DomHelper:
La clase Ext.dom.Helper nos permite agregar nuevos elementos DOM, modificar o eliminar elementos DOM
existentes en un documento HTML.
La clase DomHelper usa la sintaxis basada en JSON con los siguientes atributos especiales para crear nuevos
elementos DOM.
Atributo Descripción

Tag Etiqueta HTML del element a crear

Children o cn Un array del mismo tipo elementos de definición de etiquetas

Cls Atributo de clase de un elemento.

Html Valor innerHTML del elemento

Id El id del elemento
El siguiente ejemplo muestra cómo crear elementos DOM usando la clase Ext.DomHelper.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="../../ext-4.2.1/ext-4.2.1.883/ext-debug.js"></script>
<script>
Ext.onReady(function () {

var dh = Ext.DomHelper; // ExtJS DomHelper Utility Class


var listItems = {
id: 'dhlist',
tag: 'ul',
children: [{
tag: 'li',
html: 'item 1'
}, {
tag: 'li',
html: 'item 2'
}, {
tag: 'li',
html: 'item 3'
}]
}

dh.append("div1", listItems);
});
</script>
</head>
<body>
<div id="div1">

</div>
</body>
</html>

Componente Ext JS:


Una interfaz de usuario de la aplicación Ext JS se compone de uno o más widgets llamados Componentes.
Componente es un grupo de elementos DOM con funcionalidad compleja. Todos los componentes Ext JS
heredan de la clase Ext.Component. ExtJS proporciona diferentes tipos de componentes listos para usar con
funciones complejas, que puede utilizar en su aplicación, como Viewport, panel, container, grid, textfield,
combobox, numberfield, etc.
Los componentes Ext JS UI derivan de la clase Ext.Component, que a su vez deriva de la clase Ext.Base.
El siguiente ejemplo demuestra la creación de un componente simple.

Ext.onReady(function () {
Ext.create('Ext.Component', {
id:'myComponent',
renderTo: Ext.getBody(),
html:'Hola Mundo!'
});

});

En el ejemplo anterior, hemos creado un componente simple utilizando el método Ext.create(). Se


representará en el cuerpo del documento y mostrará una cadena simple "¡Hola mundo!".
Todos los componentes en Ext JS se registran con la clase Ext.ComponentManager en la creación, de modo
que se puede acceder a ellos por un id utilizando el método Ext.getCmp(). Se puede acceder al componente
anterior utilizando Ext.getCmp('myComponent').
Ciclo de vida de los componentes:
Cada componente en Ext JS pasa a través de las siguientes tres etapas:

Etapa Descripción

Inicialización Registrando el componente con Ext.ComponentManager y decidiendo si un componente será


mostrado.

Renderización Creando el DOM para el componente y agregándolo a la jerarquía del DOM con los eventos,
CSS, etc..

Destrucción Eliminando los eventos, el objeto DOM y desregistrando el componente del


Ext.ComponentManager

Componentes UI de Ext JS 6:
Ext JS 6 contiene los siguientes componentes de IU listos para usar.

Nombre del Componente Nombre de la Clase xtype

ComboBox Ext.form.field.ComboBox combobox o combo

Radio Button Ext.form.field.Radio radio o radiofield

Checkbox Ext.form.field.Checkbox checkbox o checkboxfield

TextField Ext.form.field.Text textfield

Label Ext.form.Label label

Button Ext.button.Button button

DateField Ext.form.field.Date datefield

File Upload Ext.form.field.File filefield, fileuploadfield

Hidden Field Ext.form.field.Hidden hidden

Number Field Ext.form.field.Number numberfield

Spinner Ext.form.field.Spinner spinnerfield

Text Area Ext.form.field.TextArea textarea

Time Field Ext.form.field.Time timefield

Trigger Ext.form.field.Trigger triggerfield, trigger

Chart Ext.chart.CartesianChart chart


Nombre del Componente Nombre de la Clase xtype

Html Editor Ext.form.field.HtmlEditor htmleditor

xtype: Cada componente tiene un nombre simbólico llamado 'xtype'. Por ejemplo, Ext.panel.Panel tiene xtype: 'panel'.
Visite la documentación de Sencha para saber cómo se ve y cómo funciona cada componente.
Contenedores Ext JS:
Ext JS incluye componentes que pueden contener otros componentes que se denominan container. Puede agregar,
insertar o eliminar componentes del container y también organizar componentes secundarios utilizando diferentes
diseños.
Ext.container.Container es una clase base para todos los contenedores en Ext JS.
Añadiendo componentes al contenedor:
Puede agregar diferentes tipos de componentes Ext JS en un contenedor utilizando la configuración de elementos o el
método add().
Nota: El contenedor también puede incluir otro contenedor.
El siguiente ejemplo muestra cómo agregar componentes a un contenedor utilizando elementos config y el método add().

Ext.onReady(function () {
var comp1 = Ext.create('Ext.Component', {
html:'Component 1'
});

var comp2 = Ext.create('Ext.Component', {


html: 'Component 2'
});

var comp3 = Ext.create('Ext.Component', {


html: 'Component 3'
});

var comp4 = Ext.create('Ext.Component', {


html: 'Component 4'
});

var container1 = Ext.create('Ext.container.Container', {


style: { borderColor: 'Red', borderStyle: 'solid', borderWidth: '1px' },
width: '50%',
padding: '5 5 5 5',
items: [comp3, comp4]
});

// agregando componentes en el contenedor usando elementos config


var container2 = Ext.create('Ext.container.Container', {
renderTo: Ext.getBody(),
title: 'Container',
border: 1,
width: '50%',
padding:'5 5 5 5',
style: {borderColor: '#000000', borderStyle: 'solid', borderWidth: '1px' },
items: [comp1, comp2]
});

// Agregar el contenedor al contenedor


container2.add(container1);
});
En el ejemplo anterior, comp3 y comp4 se agregan a container1 utilizando la propiedad config de los elementos, mientras
que container2 incluye comp1 y comp2. El container1 también agrega container2 usando el método add(). El ejemplo
anterior sería el resultado de la siguiente manera.

Nota: Los contenedores son iguales en Ext JS 4.x, 5.xy 6.x. La única diferencia es que la versión incremental proporciona
más propiedades y métodos de configuración.
Contenedores Ext JS 6:
La siguiente tabla enumera todos los contenedores importantes en Ext JS 6.

Nombre de la Clase xtype Descripción

Ext.container.Viewport viewport ViewPort es un contenedor especializado que representa el área de


aplicación visible (la ventana de visualización del navegador). En
general, hay un único ViewPort en una aplicación Ext JS que definirá las
áreas principales de la aplicación como norte, oeste, sur, este y centro.

container container Container es un contenedor liviano que proporciona una funcionalidad


básica para contener elementos, es decir, agregar, insertar y eliminar
elementos. Utilice este contenedor cuando solo desee agregar otros
componentes y organizarlos.

Ext.panel.Panel panel El panel es un tipo especial de contenedor que tiene funciones y


componentes específicos. Cada panel tiene componentes header, tool,
body, toolbar. Utilice el Panel cuando desee una interfaz de usuario
específica con header, toolbar y parte del cuerpo. No lo use si no quiere
estas características en el panel, use container en su lugar.

Ext.form.Panel form Ext.form.Panel proporciona contenedores estándar para form. Úselo


cuando quiera un formulario de aplicación estándar tipo interfaz de
usuario.

Ext.form.FieldContainer fieldcontainer FieldContainer implementa mixins que se pueden etiquetar para que se
puedan representar con una etiqueta y un mensaje de error en cada
componente sub-elemento. Puede utilizar fieldcontainer en el
formulario para organizar los campos internos.

Ext.form.FieldSet fieldset Fieldset es un contenedor para un grupo de campos en un


Ext.form.Panel.

Ext.grid.Panel grid Grid muestra una gran cantidad de datos tabulares con clasificación,
filtrado y otras funciones.
Nombre de la Clase xtype Descripción

Ext.container.ButtonGroup buttongroup ButtonGroup proporciona un contenedor para organizar un grupo de


botones relacionados de manera tabular.

Ext.tab.Panel tabpanel Ext.tab.Panel es un contenedor de pestañas básico. Úselo cuando


desee una pestaña o asistente en su interfaz de usuario.

Ext.tree.Panel treepanel TreePanel proporciona una representación de UI estructurada en árbol


de datos estructurados en árbol.

Ext.menu.Menu menu Menú es un contenedor al que puede agregar elementos de menú.

Ext.toolbar.Toolbar toolbar La barra de herramientas es un contenedor para toolbar buttons, text,


fill, ítem, etc
Ext JS proporciona diferentes tipos de diseños para organizar componentes secundarios en un contenedor.
Aprende sobre los diseños en la siguiente sección.
Diseños en Ext JS:
Cuando agrega un componente UI dentro de un contenedor, necesita definir sus propiedades de diseño. El diseño le dice
a un contenedor cómo organizar un componente secundario. Para utilizar un diseño, su componente debe ser del tipo
Ext.container.Container o algo que se herede de él. Todos los diseños heredan de Ext.layout.container.Container.
Puede establecer el diseño como una cadena o un objeto:

layout: 'auto'
//o
layout: {
type: 'auto'
}

Los siguientes son diferentes diseños disponibles en Ext JS:

Layout/diseño Descripción

Absolute Este diseño hereda el diseño de anclaje y agrega la capacidad de posicionar el componente en
coordenadas particulares utilizando las opciones de configuración estándar de x, y.

Accordion Este diseño gestiona múltiples paneles en un estilo de acordeón expandible. Por defecto, un panel
puede expandirse en cualquier momento dado, pero también puede expandir múltiples paneles
usando la configuración múltiple.

Anchor Este diseño permite el anclaje de elementos contenidos en relación con las dimensiones del
contenedor. Por favor, visite Anchor Rules.

Auto Este diseño es aplicable cuando no se configura ningún diseño en un contenedor. AutoLayout
proporciona solo una transferencia de las llamadas de diseño a los contenedores secundarios.

Border Este es un estilo de diseño de interfaz de usuario orientado a la aplicación de múltiples paneles que
admite múltiples paneles anidados, barras automáticas entre regiones y la expansión y el colapso
integrados de las regiones.

Card Este diseño gestiona múltiples componentes secundarios, cada uno de ellos instalado en el
contenedor, donde solo un único componente secundario puede ser visible en un momento dado.
Este estilo de diseño se usa más comúnmente para los asistentes y las implementaciones de
pestañas.

Fit Este diseño se utiliza en un contenedor que contiene un solo elemento que se expande
automáticamente para llenar el contenedor.
Layout/diseño Descripción

Form Este es un diseño que representará campos de formulario, uno debajo del otro, todo estirado hasta
el ancho del contenedor.

HBox Un diseño que organiza los elementos horizontalmente a través de un contenedor. Align, Flex y
Pack son importantes opciones de configuración para este diseño.

Table Este diseño le permite representar fácilmente el contenido en una tabla HTML.

VBox Un diseño que organiza los elementos verticalmente en un contenedor. Align, Flex y Pack son
importantes opciones de configuración para este diseño.

El siguiente ejemplo muestra el diseño de componentes secundarios horizontal y verticalmente en un


contenedor.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="../../ext-4.2.1/ext-4.2.1.883/ext-debug.js"></script>
<link href="../../ext-4.2.1/ext-4.2.1.883/resources/css/ext-all.css" rel="stylesheet"
/>
</head>
<body>
<script>
Ext.onReady(function () {

var comp1 = Ext.create('Ext.Component', {


html: 'Component 1',
padding:'5 5 5 5'
});

var comp2 = Ext.create('Ext.Component', {


html: 'Component 2',
padding: '5 5 5 5'
});
var comp3 = Ext.create('Ext.Component', {
html: 'Component 3',
padding: '5 5 5 5'
});
var comp4 = Ext.create('Ext.Component', {
html: 'Component 4',
padding: '5 5 5 5'
});

var container = Ext.create('Ext.container.Container', {


layout: {type: 'vbox'},
items: [comp3, comp4]
});

Ext.create('Ext.container.Container', {
style: {borderColor: 'Red', borderStyle: 'solid', borderWidth: '1px'},
renderTo: Ext.getBody(),
padding: '5 5 5 5',
layout: {type: 'hbox'},
items: [comp1, comp2, container]

});

});
</script>
</body>
</html>

Visite Layouts Example para obtener más información práctica sobre diseños.
ComponentQuery:
Ext JS proporciona la clase Singleton Ext.ComponentQuery para buscar componentes en la página HTML con
una sintaxis similar a un selector CSS.
La clase Ext.ComponentQuery proporciona diferentes métodos para realizar diferentes tareas. Por ejemplo,
agregar propiedades en una clase componente, crear un objeto de un componente, obtener propiedades de
configuración de un componente, consultar componentes de búsqueda, etc.
Los componentes se pueden recuperar de las siguientes maneras.
Query Type Descripción

xtype Los componentes pueden ser recuperados por su xtype.

itemId or id Los componentes pueden ser recuperados por su id o itemId. La identificación debe tener el prefijo #.

Attributes Los componentes pueden ser recuperados por sus atributos o propiedades config.

descendant Los componentes pueden ser recuperados por el descendiente.

Direct child Los componentes pueden ser recuperados por la relación hijo directo.

Parent Ext.ComponentQuery.query('textfield ^ panel'); // Recupera todos los paneles que sean padre de un
textfield.

El siguiente ejemplo muestra cómo buscar componentes utilizando el método Ext.ComponentQuery.query().


Ext.onReady(function () {

Ext.create('Ext.container.Container', {
id:'myContainer',
renderTo: Ext.getBody(),
padding: '5 5 5 5',
layout: { type: 'vbox' },
items: [
{
xtype: 'textfield',
fieldLabel:'Nombre'
},
{
xtype: 'textfield',
fieldLabel: 'Apellido'
},
{
xtype: 'panel',
layout:'vbox',
items: [
{
xtype: 'datefield',
fieldLabel: 'Fech de Nac.'
},
{
xtype: 'container',
items: [
{
xtype: 'textfield',
fieldLabel: 'email',
itemId:'email'
}
]
}
]
}

});

var dateFields = Ext.ComponentQuery.query('container datefield');


console.log('DateField en Contenedores: ');
console.log(dateFields);
var dateFieldsInPanels = Ext.ComponentQuery.query('panel > datefield');
console.log('DateField hijos en el Panel: ' );
console.log(dateFieldsInPanels);

var emailInMyContainer = Ext.ComponentQuery.query('#myContainer > #email');


console.log('#email inside #myContainer');
console.log(emailInMyContainer);
});

En el ejemplo anterior, la primera consulta 'container datafield' busca todos los componentes del campo de
fecha dentro de cualquier contenedor en un documento.
La segunda consulta 'panel> datafield' busca todos los campos de fecha que son hijos directos del panel.
La tercera consulta '#myContainer #email' busca el componente cuya id es 'email' dentro de un contenedor
cuya id es 'myContainer'.
Consulte la documentación de Sencha para obtener más información sobre Ext.ComponentQuery.

Ext JS Viewport:
Viewport en Ext JS es un contenedor especializado que representa el área de aplicación visible en el navegador.
Solo puede haber una ventana gráfica en la aplicación de una sola página ExtJS 4.
El Viewport representa al cuerpo del documento y se redimensiona automáticamente al tamaño de la ventana
del navegador y administra el cambio de tamaño de la ventana.
Vamos a crear una ventana gráfica en una aplicación Ext JS.
Primero, crea una app.js como se muestra a continuación.
Ext.application({
name: 'School',
mainView: 'School.view.Viewport'
});

En el archivo app.js anterior, config del mainView indica la vista inicial que se debe representar. Aquí, es una
vista de clase School.view.Viewport. Usaremos el kit de herramientas clásico para nuestra aplicación de
muestra. Entonces, crea una carpeta classic y una carpeta view dentro de la carpeta classic.
En la carpeta view, cree Viewport.js y defina la clase Schoo.view.Viewport como se muestra a continuación.
Ext.define('School.view.Viewport', {

extend: 'Ext.container.Viewport',
alias: 'widget.StudentViewport',
requires: ['Ext.menu.Menu','School.view.ViewportController'],
controller:'viewport',
config: {},
constructor: function(config) {
return this.callParent(arguments);
},

initComponent: function) {
Ext.apply(this, {
id: 'StudentViewportID',
title: 'Student Information',

layout: {
type: 'border'
},
items: [{
region: 'north',
border: false,
margins: '0 0 5 0',
items: [{
xtype: 'container',
html: '<h1 class="x-panel-header">extjs-tutorial.com</h1>'
}, {
xtype: 'toolbar',
itemId: 'schoolToolbar',
enableOverflow: true,
items: [{
xtype: 'button',
// por defecto para las barras de herramientas-toolbars
text: 'Add Tab',
itemId: 'btnAddtabs',
listeners: {
click: 'onAddTab'
}
}, {
xtype: 'button',
// por defecto para las barras de herramientas
text: 'Add Window',
itemId: 'btnAddwindow',
listeners: {
click: 'onAddWindow'
}

}, {
xtype: 'splitbutton',
text: 'Split Button'
},

'->',
{
xtype: 'textfield',
name: 'field1',
emptyText: 'enter search term'
},
'-',
'text 1',
{
xtype: 'tbspacer'
},
'text 2', {
xtype: 'tbspacer',
width: 50
},
'text 3']
}]
}, {
region: 'west',
collapsible: true,
title: 'Navigation',
width: 150,
split: true,
items: [{
xtype: 'menu',
width: 150,
plain: true,
floating: false,
showSeparator: true,

items: [{
text: 'Menu item 1'

}, {
xtype: 'menuseparator'
}, {
text: 'Menu item 2'
}, {
xtype: 'menuseparator'
}, {
text: 'Menu item 3'
}]
}]

}, {
region: 'south',
title: 'South Panel',
collapsible: true,
html: 'Aqui ira información',
split: true,
height: 100,
minHeight: 100
}, {
region: 'east',
title: 'Panel Este',
split: true,
width: 150
}, {
region: 'center',
xtype: 'tabpanel',
activeTab: 0,
items: [{
title: 'Default Tab',
html: 'El contenido de la primera pestaña. Otros pueden ser agregados dinámicamente '
}, {
title: 'Segundo Tab',
html: ' El contenido de la segunda pestaña. Otros pueden ser agregados dinámicame
nte. '
}]
}]
});

this.callParent(arguments);
}

});

En la clase Viewport anterior, incluye diferentes regiones para separar diferentes secciones de la vista de la
aplicación, como encabezado, barra izquierda, barra derecha, área central y área de pie de página.
Ext.container.Panel es el xtype predeterminado en la colección de elementos de Viewport.

Ahora, para manejar los eventos de la clase viewport anterior, agregue la clase ViewportController. Para eso,
cree la aplicación -> view -> ViewportController.js y defina la clase School.view.ViewportController como se
muestra a continuación.
Ext.define('School.view.ViewportController', {
extend: 'Ext.app.ViewController',

alias: 'controller.viewport',

onAddWindow: function(sender, record) {


Ext.Msg.alert('Agregar Ventana, 'Agrega una nueva ventana aquí.');
},

onAddTab: function(choice) {
Ext.Msg.alert('Agregar Tab', 'Agrega un nuevo tab aquí.');
}
});

Visite la documentación de Sencha para obtener más información sobre Viewport.

MessageBox:
Puede visualizar muchos tipos de cuadros de mensajes en Ext JS. Ext.window.MessageBox es la clase principal
para crear un cuadro de mensaje en Ext JS.
Ext.MessageBox o Ext.Msg es una instancia única de Ext.window.MessageBox. No es necesario crear un objeto
Ext.window.MessageBox para mostrar el cuadro de mensaje todo el tiempo.
A diferencia de una alerta de JavaScript normal (que detiene la ejecución del navegador), mostrar un cuadro
de mensaje con Ext.Msg no hará que el código se detenga. Si tiene un código que debe ejecutarse después de
la acción del usuario desde el cuadro de mensaje, debe especificar una función de devolución de llamada.
Puede mostrar cuatro tipos de cuadros de mensaje:
Alerta-Alert: muestra un cuadro de mensaje de solo lectura estándar con un botón Aceptar.
Confirmar-Confirm: muestra un cuadro de mensaje de confirmación con los botones Sí y No.
Solicitud-Prompt: muestra un cuadro de mensaje con los botones Aceptar y Cancelar que le solicitan al usuario
ingresar algún texto (similar a la solicitud de JavaScript). Puede ser un cuadro de texto de una sola línea o de
varias líneas.
Personalizado-Custom: estilo de cuadro de mensaje personalizado.

Veamos un ejemplo de cada tipo:

Singleton Alert:
Puede mostrar la alerta usando 'Ext.Msg', que es una forma corta de la clase singleton 'Ext.MessageBox'.
Ext.Msg.alert('Estado', 'Este es un cuadro de mensaje en Ext JS.');

Nota: Si tiene dos mensajes de alerta consecutivos usando 'Ext.Msg', entonces se mostrará el último mensaje
de alerta porque Ext.Msg es una clase singleton.
Ext.Msg.alert('Estado', 'Este es el primer cuadro de mensaje Ext JS.');

Ext.Msg.alert('Estado', 'Este es el segundo cuadro de mensaje Ext JS.');

En el ejemplo anterior, verá solo un cuadro de mensaje con el mensaje 'Este es el segundo cuadro de mensaje
Ext JS'.

También puede crear un objeto de Ext.window.MessageBox y llamar al método de alerta como se muestra a
continuación:
var msg = Ext.create('Ext.window.MessageBox');

msg.alert('Estado', 'Este es un cuadro de mensaje en Ext JS.');

Confirm:
El cuadro de mensaje de confirmación (confirm) muestra el mensaje con los botones Sí y No. También puede
capturar usuarios haciendo clic en el evento para un proceso posterior.
Ext.Msg.confirm("Confirmación", "Desea cuardar los cambios?", function(btnText){
if(btnText === "no"){
Ext.Msg.alert("Alerta", " Has confirmado 'No'.");
}
else if(btnText === "yes"){
Ext.Msg.alert("Alerta", " Has confirmado 'Si'.");
}
}, this);

Prompt:
El indicador muestra un cuadro de mensaje con los botones Aceptar y Cancelar que le solicitan al usuario
ingresar algún texto.
Ext.Msg.prompt("Tutorial Ext JS", "Ingrese su Sencha Id:", function(btnText, sInput){
if(btnText === 'ok'){
Ext.Msg.alert("Status", "Ingresó:" + sInput);
}
}, this);

Custom Message Box


Puede personalizar un cuadro de mensaje según sus necesidades pasando diferentes opciones de
configuración.
Ext.Msg.show({
title: 'Guardar',
msg: 'Desea guardar los cambios? ',
width: 300,
closable: false,
buttons: Ext.Msg.YESNOCANCEL,
buttonText:
{
yes: 'Yes & Continue',
no: 'No & Continue',
cancel: 'Discard'
},
multiline: false,
fn: function(buttonValue, inputText, showConfig){
Ext.Msg.alert('Status', buttonValue);
},
icon: Ext.Msg.QUESTION
});

ProgressBar in Ext JS:


Puede mostrar la barra de progreso en ExtJS 4 usando la clase Ext.ProgressBar. Soporta dos modos diferentes:
Manual y Automático.
En el modo manual, usted es responsable de mostrar, actualizar (a través de updateProgress) y borrar la barra
de progreso según sea necesario desde su propio código. Este método es más apropiado cuando desea mostrar
el progreso a lo largo de la operación que tiene puntos de interés predecibles en los que puede actualizar el
control.
A continuación, se muestra un ejemplo de la barra de progreso manual que usa el método updateProgress:
for(var i = 0; i < 11; i ++ ){
progBar.updateProgress((i * 0.1), 'actualizando', 'guardando..');
// Escribir código que lleve tiempo para ejecutar en cada iteración
}
progBar.updateText('Guardado Exitosamente!');

Barra de progreso automática utilizando el método de espera:


progBar.wait({
duration: 10000,
increment: 12,
text: 'Guardando...',
scope: this,
fn: function(){
progBar.updateText('Guardado exitosamente!');
}
});

También puede usar Ext.MessageBox para mostrar la barra de progreso automático de la siguiente manera:
Ext.MessageBox.show({
msg: 'Guardando Cambios, espere...',
progressText: 'Guardando...',
width: 300,
wait: true,
waitConfig:
{
duration: 10000,
increment: 15,
text: 'Guardando...',
scope: this,
fn: function(){
Ext.MessageBox.hide();
Ext.Msg.alert('Estado', 'Guardad exitosamente!');
}
}
});

Visite la documentación de Sencha para obtener más información sobre la barra de progreso.

AVANZADO

Paquete de datos Ext JS (Data Package):


Ext JS incluye el paquete de datos Ext.data incluye clases que se ocupan de guardar y recuperar datos del
servidor.
Las siguientes son clases importantes en el paquete de datos de Ext JS 6:
1. Model (Ext.data.Model)
2. Store (Ext.data.Store)
3. Proxy (Ext.data.proxy.Proxy)
4. Session (Ext.data.Session)
La siguiente figura ilustra la interacción entre clases importantes de paquetes de datos.

Según la figura anterior, la clase model incluye un proxy que obtiene el registro único del servidor para
mostrarlo en la vista Form Ext JS. De la misma manera, el Store incluye el model y el proxy para obtener la
colección de registros del servidor remoto para mostrarlos en la Grid view. Tenga en cuenta que el proxy puede
asociarse con la clase model o la clase store.

Model:
La clase Ext.data.Model define la forma de los datos. Una definición model incluye campos, validaciones y
métodos. Es M en la arquitectura MVC y MVVM .
La clase model debe crearse en la carpeta Model. Por ejemplo, para definir la clase de model Student, cree
Student.js en la carpeta app -> model en Ext JS 6 como se muestra a continuación.
La clase model debe derivarse de la clase Ext.data.Model. La siguiente es una clase model student con
diferentes campos.
Ext.define('Student', {
extend: 'Ext.data.Model',
idProperty:'Id',
fields: [
{name: 'Id', type: 'int'},
'firstName',
'lastName'
]
});

La clase de model Student anterior amplía Ext.data.Model. Define 3 campos: ID, (first name) nombre y (last
name) apellido utilizando la configuración de "fields". Especifique el tipo de un campo usando la propiedad
type de un campo. Si no especifica el tipo, entonces el tipo predeterminado sería string. Ext JS admite
diferentes tipos de campo, como auto, int, string, float, boolean y date.
El siguiente ejemplo muestra el modelo student con validaciones.
Ext.define('Student', {
extend: 'Ext.data.Model',
idProperty:'Id',
fields: [
{name: 'Id', type: 'int'},
'firstName',
'lastName'
],
validators: {
firstName: 'presence',
lastName: {type: 'length', min: 2}
}
});

En el ejemplo anterior, hemos definido la clase model Student con los campos Id, firstName y lastName. La
configuración 'validators' define validaciones para campos.
Puede crear un registro creando un objeto de modelo student y especificar los valores de los campos. El
método isValid() determina si un registro satisface todos los validadores o no, como se muestra a continuación.
var studentRecord = Ext.create('Student',{
firstName:'',
lastName: 'J'
});

if (!studentRecord.isValid())
{
var validation = studentRecord.getValidation();
console.log('Nombre: ' + validation.get('firstName'));
console.log('Apellido: ' + validation.get('lastName'));
}

ExtJS 5 incluye los siguientes validators fuera del cuadro.


Validator Descripción
Email Valida que el valor sea un id de correo electrónico válido.
Exclusion Valida que el valor no exista en una lista de valores.
Format Valida que el valor pasado coincida con un formato específico mediante una
expresión regular.
Inclusion Valida que el valor exista en una lista de valores.
Length Valida que la longitud del valor esté entre un mínimo y un máximo.
Presence Valida que el valor pasado no sea nulo o indefinido o ' '.
Range Valida que el valor esté entre un mínimo y un máximo.

Tipo de campo personalizado:


Como se mencionó anteriormente, el model Ext JS puede incluir tipos de campos predeterminados como auto,
int, string, float, Boolean y date. También podemos definir un nuevo tipo de campo personalizado con
validación que se puede usar en varios modelos.
El tipo de campo personalizado se puede definir heredando de los tipos de campo existentes. El siguiente
ejemplo demuestra la creación de un nuevo tipo de campo 'Género'.
Ext.define('Gender', {
extend: 'Ext.data.field.String',
alias: 'data.field.gender',
validators: {
type: 'inclusion',
list: [ 'femenino', 'masculino']
}
});

Ahora, el tipo de campo anterior se puede utilizar con cualquier modelo como se muestra a continuación.
Ext.define('Student', {
extend: 'Ext.data.Model',
idProperty:'Id',
fields: [
{name: 'Id', type: 'int'},
'firstName',
'lastName',
{name:'gender', type:'gender'} // usa el campo personalizado
]
});
var studentRecord = Ext.create('Student',{
firstName:'James',
lastName: 'Bond',
gender:'TEST'
});

if (!studentRecord.isValid())
{
var validation = studentRecord.getValidation();

console.log('Género: ' + validation.get('gender'));


}

Visite Sencha Docs para saber más sobre Ext.data.Model

Asociación entre modelos:


Ext JS proporciona una manera fácil de definir asociaciones entre modelos. Veamos cómo definir las
relaciones uno a uno, uno a muchos y muchos a muchos.

Uno a uno:
El siguiente ejemplo muestra cómo definir una relación uno a uno entre dos modelos.

Ext.define('Address', {
extend: 'Ext.data.Model',

fields: [
{ name: 'addressId', type: 'int' },
'address',
'city',
'state'
],
identifier: {
type: 'negative'
}

});

Ext.define('Student', {
extend: 'Ext.data.Model',

idProperty:'Id',
fields: [
{ name: 'Id', type: 'int' },
'firstName',
'lastName',
{ name:'addressId', reference:'Address', unique: true}
],
identifier: {
type: 'negative'
}

});

var studentRecord = Ext.create('Student',{


firstName:'James',
lastName: 'Bond'
});

var address = Ext.create('Address', {


address: 'Y Street'
})

studentRecord.address = address;

En el ejemplo anterior, el modelo Student incluye un campo 'addressId' archivado con la referencia de
'Address' y lo configura como único. Esto hace la relación uno a uno entre el modelo estudiante y dirección.

Uno a muchos:
Hay dos formas de definir relaciones de uno a muchos en Ext JS, usando la configuración hasMany de Ext JS 4
o la nueva configuración de referencia.
El siguiente ejemplo muestra cómo definir una relación de uno a muchos usando la configuración hasMany.

Ext.define('Student', {
extend: 'Ext.data.Model',

idProperty:'Id',
fields: [
{name: 'Id', type: 'int'},
'firstName',
'lastName'
],
identifier: {
type: 'negative'
},

hasMany: {
name: 'Courses',
model:'Course'
}
});

Ext.define('Course', {
extend: 'Ext.data.Model',
idProperty: 'Id',
fields: [
{name: 'Id', type: 'int'},
'courseName'
],
identifier: {
type: 'negative'
}
});

var course1 = Ext.create('Course', {


courseName: 'Ext JS 4'
})

var course2 = Ext.create('Course', {


courseName: 'Ext JS 5'
})
var studentRecord = Ext.create('Student',{
firstName:'James',
lastName: 'Bond'
});

var courses = studentRecord.Courses();


courses.add(course1);
courses.add(course2);

Muchos a muchos:
Ext JS proporciona una manera fácil de definir relaciones de muchos a muchos entre modelos que utilizan la
configuración manyToMany.

El siguiente ejemplo muestra cómo definir relaciones de muchos a muchos:

Ext.define('Student', {
extend: 'Ext.data.Model',

idProperty:'Id',
fields: [
{ name: 'Id', type: 'int' },
'firstName',
'lastName'
],
identifier: {
type: 'negative'
},
manyToMany: 'Course'
});

Ext.define('Course', {
extend: 'Ext.data.Model',
idProperty: 'Id',
fields: [
{ name: 'Id', type: 'int' },
'courseName'
],
identifier: {
type: 'negative'
}
});

var course1 = Ext.create('Course', {


courseName: 'Sencha Touch'
})

var course2 = Ext.create('Course', {


courseName: 'Sencha Architect'
})
var studentRecord = Ext.create('Student',{
firstName:'steve',
lastName: 'Jobs'
});

var course1 = Ext.create('Course', {


courseName: 'ExtJS 4'
});

var course2 = Ext.create('Course', {


courseName: 'ExtJS 5'
});

var course3 = Ext.create('Course', {


courseName: 'ExtJS 6'
});

var student1 = Ext.create('Student', {


firstName: 'Bob',
lastName: 'Friss'
});
var student2 = Ext.create('Student', {
firstName: 'James',
lastName: 'Bond'
});

var student3 = Ext.create('Student', {


firstName: 'Sachin',
lastName: 'Tendulkar'
});

var courses = student1.courses();


courses.add(course1);
courses.add(course2);

var students = course3.students();


students.add(student2);
students.add(student3);

Ext JS ViewModel:
En la sección anterior, aprendiste sobre el modelo. El modelo juega un papel importante en la arquitectura
MVC. Ext JS admite la arquitectura MVVM (Model-View-ViewModel) ya que Ext JS 5 y ViewModel es una
parte importante de la arquitectura MVVM.

ViewModel es una clase que administra datos para un componente de IU específico. Puede pensarlo como
un contenedor de un registro para la vista específica. Admite el enlace de datos bidireccional con el
componente UI, por lo que, tan pronto como el usuario cambia los datos en la vista (view), tiene una copia
más reciente. A diferencia del modelo, no puede incluir proxy, por lo que no puede obtener datos
directamente del servidor remoto.

Vamos a crear un ViewModel simple con datos ficticios y vincularlo a un componente. Considere el siguiente
ejemplo.

Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',

alias: 'viewmodel.test',

data: {
id: 1,
name: 'Steve'
}
});

Ext.create('Ext.Component', {

viewModel:{
type:'test'
},

bind:{
html:'{id} - {name}'
},

renderTo:Ext.getBody()
});
En el ejemplo anterior, hemos creado una clase simple ViewModel llamada MyApp.view.TestViewModel y
extendida de Ext.app.ViewModel. La configuración de alias se utiliza para darle un nombre corto para que
podamos referenciar con este nombre corto en la interfaz de usuario. La configuración (config) de datos (data)
se utiliza para proporcionar un objeto de datos test. Aquí, hemos proporcionado un objeto simple con
propiedades id y name. Se hace referencia a la clase viewmodel en un componente usando config viewModel
con el tipo de viewmodel. Use config bind para vincular el valor específico de la configuración de la interfaz de
usuario con los datos de ViewModel. En el ejemplo anterior, la propiedad html del componente se enlaza con
la propiedad id y name del objeto de datos del viewmodel "test". Use llaves para unir una propiedad particular
como '{id}' o '{name}'. Así que ahora, el componente anterior mostrará "1 - Steve".

Ahora, vamos a crear un ViewModel simple en la arquitectura Ext JS MVVM.


Una clase ViewModel debe crearse en un archivo JS separado en la carpeta view. Por ejemplo, ViewModel
para Student debe crearse en la carpeta app -> view -> student en la arquitectura Ext JS MVVM como se
muestra a continuación.

La clase de ViewModel personalizada debe heredar de la clase Ext.app.ViewModel.


La siguiente es la clase StudentViewModel de muestra.
Ext.define('MyExtJSApp.StudentViewModel', {
extend: 'Ext.app.ViewModel',
alias:'viewmodel.studentviewmodel',

data: {
firstName: 'James',
lastName:'Bond'
},
formulas: {
fullName: function(get){
return get('firstName') + ' ' + get('lastName');
}
}
});

En el ejemplo anterior, hemos creado una clase StudentViewModel que extiende de la clase
Ext.app.ViewModel. La configuración de alias asigna un nombre, por lo que podemos referirnos a ella
utilizando un alias en lugar del nombre completo de la clase. La configuración (config) de datos (data) se utiliza
para asignar datos arbitrarios como un objeto. Hemos especificado dos propiedades, firstName y lastName.
ViewModel se puede asociar con uno o más componentes de UI. Podemos usar la propiedad de configuración
de enlace bind para enlazar datos entre el ViewModel y el componente.
El siguiente componente del form vincula las propiedades firstName y lastName del StudentViewModel
anterior con los campos de texto (textfields).
Ext.application({
name: 'SchoolApp',
requires: ['SchoolApp.StudentViewModel'],

launch: function() {
Ext.create('Ext.container.Viewport', {

items: [{
xtype: 'form',
layout:'form',
bodyPadding: '5',
buttonAlign: 'center',

viewModel: {
type: 'StudentViewModel'
},

items: [{
xtype: 'textfield',
fieldLabel: 'Nombre',
bind: {
value: '{firstName}'
}
}, {
xtype: 'textfield',
fieldLabel: 'Apellido',
bind: {
value: '{lastName}'
}
}, {
xtype: 'displayfield',
fieldLabel: 'Nombre Completo',
bind: {
value: '{fullName}'
}
}],
buttons: [{
text: 'Guardar'
}, {
text: 'Cancelar'
}]

}]

})
}
});
Links:
ViewModel incluye la configuración de enlaces links que le da un nombre a un registro específico.

Por ejemplo, la siguiente configuración de enlaces links se usa para dar un nombre a un registro de Estudiante
cuya identificación es 5.
Ext.define('SchoolApp.view.student.StudentViewModel', {
extend: 'Ext.app.ViewModel',
alias:'viewmodel.StudentViewModel',

formulas: {
fullName: function(get){
return get('theStudent.firstName') + ' ' + get('theStudent.lastName');
}
},
links: {
theStudent: {
type: 'Student',
id:5
}
}
});

ViewModel carga el registro de la clase de modelo fuente-Estudiante configurada en este caso. theStudent usa
la clase de modelo de Student para obtener el registro del servidor remoto.
model\Student.js
Ext.define('SchoolApp.model.Student', {
extend: 'Ext.data.Model',
idProperty: 'Id',

schema: {
namespace: 'SchoolApp.model',
proxy: {
type:'ajax',
api: {
read: '/ExampleService.svc/students/'
},
reader:{
type:'json',
rootProperty:'data'
}
}
},
fields: [
{ name: 'Id', type: 'int' },
{ name: 'firstName', type: 'string' },
{ name: 'middleName', type: 'string' },
{ name: 'lastName', type: 'string' },
{ name: 'birthDate', type: 'date' },
{ name: 'address1', type: 'string' },
{ name: 'address2', type: 'string' },
{ name: 'city', type: 'string' },
{ name: 'state', type: 'string' }
]

});
Stores:
ViewModel incluye config de Stores que definen un nuevo store o un store encadenado.
El siguiente ejemplo demuestra la definición de store en el ViewModel.
Ext.define('SchoolApp.view.student.StudentViewModel', {
extend: 'Ext.app.ViewModel',
alias:'viewmodel.StudentViewModel',
formulas: {
fullName: function(get){
return get('firstName') + ' ' + get('lastName');
}
},
stores: {
students: {
model: 'Student',
autoLoad: true,
sorters: [{
property: 'firstName',
direction:'DESC'
}]
}
}

});

En el ejemplo anterior, el store "students" se puede usar para enlazar a un componente del grid.

ViewController:
El controlador (Ext.app.Controller) en ExtJS 4.x se usa para manejar eventos de múltiples componentes
utilizando selectores similares a CSS para hacer coincidir los componentes y responder a sus eventos.
El ViewController (Ext.app.ViewController) se introdujo desde Ext JS 5. ViewController está asociado con un
componente específico de la interfaz de usuario y maneja los eventos provocados por ese componente en
particular sin usar refs (como en Ext JS 4).
ViewController se puede crear en un archivo JS separado en la misma carpeta donde se encuentra el view. Por
ejemplo, StudentViewController para la vista StudentMaster debe crearse en la carpeta app -> view -> de
students.
El siguiente ejemplo muestra StudentViewController que maneja los eventos del componente StudentMaster.
Ext.define('SchoolApp.view.student.StudentViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.StudentViewController',

init: function (view) {

},

onReadClick: function () {
this.lookupReference('firstName').setValue('Steve');
this.lookupReference('lastName').setValue('Jobs');

Ext.Msg.alert('Status', 'Read button clicked.');


},

onSaveClick: function () {
Ext.Msg.alert('Status', 'Save button clicked.');

},

onResetClick: function () {
this.lookupReference('firstName').setValue('');
this.lookupReference('lastName').setValue('');

Ext.Msg.alert('Status', 'Reset button clicked.');


},

onExitClick: function () {
Ext.Msg.alert('Status', 'Exit button clicked.');
this.getView().destroy();
}

});

El siguiente es un componente StudentMaster que usa el StudentViewController anterior.


Ext.define('SchoolApp.view.student.StudentMaster', {
extend: 'Ext.form.Panel',
alias: 'widget.StudentMaster',

config: {},
requires: ['SchoolApp.view.student.StudentViewController'],
title: 'Información del Estudiante',

constructor: function (config) {


return this.callParent(arguments);
},

controller: 'StudentViewController',

initComponent: function () {

Ext.apply(this, {

resizable: false,
collapsible: true,
bodyPadding: '5',
buttonAlign: 'center',
border: false,
layout: 'anchor',
defaults: {
anchor: '100%'
},
items: [{
xtype: 'textfield',
fieldLabel: 'First Name',
reference: 'firstName'
},
{
xtype: 'textfield',
fieldLabel: 'Last Name',
reference: 'lastName'
}
],
buttons: [{
text: 'Read', itemID: 'btnRead',
listeners: {
click: 'onReadClick'
}
},
{
text: 'Save', itemID: 'btnSave',
listeners: {
click: 'onSaveClick'
}
},
{
text: 'Reset',
listeners: {
click: 'onResetClick'
}
},
{
text: 'Exit',
listeners: {
click: 'onExitClick'
}
}

});

this.callParent(arguments);
}
});

En el ejemplo anterior de StudentMaster, StudentMaster incluye la configuración del controlador que apunta
a ViewController. Aquí, StudentViewController manejará todos los eventos generados desde la vista
StudentMaster. Además, la configuración de listeners se usa para especificar el nombre del evento y el nombre
de la función del controlador que se definirá en la clase StudentViewController. Por ejemplo, el evento clic del
botón “Read” será manejado por el método onReadClick definido en StudentViewController.
La configuración de referencia se aplica con los textfields FirstName y LastName para que podamos obtener la
referencia de los textfields FirstName y LastName en StudentViewController para trabajar en ella.
Por lo tanto, es fácil vincular eventos y también obtener la referencia de cualquier componente de la interfaz
de usuario utilizando la configuración reference en ViewController.

Solicitud de AJAX (AJAX Request) en Ext JS:


Puede usar Ext.Ajax para comunicarse con el código del lado del servidor o el servicio en el mismo dominio.
Ext.Ajax es una instancia única de Ext.data.Connection que es la clase principal para configurar una conexión.
Considere el siguiente ejemplo de solicitud de Ajax:
Ext.Ajax.request({
url: '/api/students',
method: 'GET',
timeout: 60000,
params:
{
id: 1 // carga los estudiantes cuyo Id es 1
},
headers:
{
'Content-Type': 'application/json'
},
success: function (response) {

},
failure: function (response) {
Ext.Msg.alert('Estado', 'Solicitud fallida.');

}
});

En el ejemplo anterior, enviamos una solicitud HTTP GET al punto final api REST url
http://localhost/api/students utilizando el método Ext.Ajax.request(). La configuración url especifica el punto
final. El método config especifica el método HTTP. Puede ser GET, POST, PUT, DELETE u otro método HTTP
válido. La configuración params especifica el parámetro que debe ir junto con la solicitud HTTP. La
configuración success y failure se utiliza para especificar la función callback que se ejecutará si la solicitud se
ejecuta correctamente o no.
Visite Ext.data.Connection y Ext.Ajax para más información.

Session:
Ext JS 5 introdujo Ext.data.Session. La sesión puede asociarse con cualquier componente de UI, ViewModel o
Store. Administra los datos y maneja la operación CRUD, una vez que se cargan los datos.
Apply session: true config a cualquier componente de la interfaz de usuario para crear una nueva sesión y
adjuntarla. Todos los componentes secundarios pueden generarse a partir de la sesión principal actual.
Veamos un ejemplo de cómo una sesión administra los datos de dos stores y realiza la operación CRUD.
Construiremos UI con dos grids editables, students y states como se muestra a continuación. Crearemos una
sesión y la usaremos para administrar la operación CRUD para ambos grids.
Primero, cree una ventana gráfica como se muestra a continuación.
Ext.application({
name: 'SchoolApp',
autoCreateViewport: false,
views: ['SchoolApp.view.student.StudentList', 'SchoolApp.view.student.StateList'],
requires: ['SchoolApp.view.student.StudentViewModel'],

launch: function () {

Ext.create('Ext.container.Viewport', {
layout: 'border',
dock: 'top',
viewModel: {
type: 'StudentViewModel'
},
session: true,
items: [
{
region: 'north',
xtype: 'toolbar',
items: [{
text: 'Guardar lote',
handler: function () {
try {
var viewport = this.up().up();
var ses = viewport.getSession();

var batch = ses.getSaveBatch();

batch.on({
complete: function () {
Ext.Msg.alert('Estado', 'Datos guardados exitosamente!');
},
exception: function () {
Ext.Msg.alert('Error', 'Ocurrió un error');
}
});

batch.start();
}
catch (ex) {
Ext.Msg.alert('Error', ex.message);
}
}
},
{
text: 'Mostrar Cambios',
handler: function () {
var viewport = this.up().up();
var ses = viewport.getViewModel().getSession();
var changes = ses.getChanges();

if (!changes) {
Ext.Msg.alert('Estado', 'Sin Cambios');
return;
}

if (changes.State && changes.State.U) // si se actualizo el estado


{
var changedStateNames = " Nombres de Estado cambiados: ";
for (var i = 0; i < changes.State.U.length ; i++) {
changedStateNames += changes.State.U[i].name + ", ";
}

Ext.Msg.alert('Estado', changedStateNames);
}

if (changes.Student && changes.Student.U) { // si se actualiza el estudia


nte
var changedStudentNames = " Nombres de Estado cambiados: ";
for (var i = 0; i < changes.Student.U.length ; i++) {
changedStudentNames += changes.Student.U[i].firstName + ", ";
}

Ext.Msg.alert('Estado', changedStudentNames);
}
}
}]
},
{
region: 'center',
xtype: 'StudentList',
bind: { store: '{students}' },
flex: 1
},
{
xtype: 'StateList',
region: 'south',
bind: { store: '{states}' },
flex: 1
}]
});
}
});

En el ejemplo anterior, adjuntamos StudentViewModel y especificamos session:true. Viewport incluye los grids
StudentList y StateList como ítems hijos.
El siguiente es un StudentViewModel.
Ext.define('SchoolApp.view.student.StudentViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.StudentViewModel',

stores: {
students: {
model: 'SchoolApp.model.Student',
session: true,
autoLoad: true,
sorters: [{
property: 'firstName',
direction:'DESC'
}]
},
states: {
model: 'SchoolApp.model.State',
session: true,
autoLoad: true,
sorters: [{
property: 'name',
direction: 'ASC'
}]
}
}
});

En el StudentViewModel anterior, hemos especificado dos stores, students y states. También hemos
especificado la configuración de sesión para ambos stores. Esta sesión gestionará los datos cargados en stores
students y states.

Use el método de sesión getChanges() para obtener la lista de registros que han cambiado. Utilice el método
getSaveBatch() para realizar la operación CRUD en los registros modificados. El siguiente código muestra cómo
enviar registros modificados al servidor remoto.
try
{
var viewport = this.up().up();
var ses = viewport.getSession();

var batch = ses.getSaveBatch();


batch.on({
complete: function () {
Ext.Msg.alert('Estado', 'Datos guardados exitosamente!');
},
exception: function () {
Ext.Msg.alert('Error', 'Ocurrió un error');
}
});

batch.start();
}
catch (ex) {
Ext.Msg.alert('Error', ex.message);
}

En el ejemplo anterior, obtenemos la referencia del viewport y luego obtenemos la sesión de viewport usando
el método getSession(). El método getSaveBatch() devuelve Ext.data.Batch que puede usarse para realizar una
operación por lotes.
model\State.js
Ext.define('SchoolApp.model.State', {
extend: 'Ext.data.Model',
idProperty: 'Id',

proxy: {
type:'ajax',
api: {
read: '/ExampleService.svc/students/'
},
reader:{
type:'json',
rootProperty:'data'
},
writer: {
allowSingle: false
}

},
fields: [
{ name: 'Id', type: 'int' },
{ name: 'name', type: 'string' }
]
});

Store encadenado:
Ext JS 5 introdujo un nuevo tipo de store llamado store encadenado. Un store encadenado está vinculado a un
store de origen. Los registros provienen del store de origen. Un store encadenado define filters y sorters que
actúan de forma independiente sin tener ningún impacto en el almacén de origen. Sin embargo, los filters y
sorters aplicados en el store de origen también pueden tener un impacto en los store encadenados.
El store encadenado se puede definir en un archivo JS separado, así como en un ViewModel.
Veamos un ejemplo de cómo se puede crear un nuevo store encadenado que no tenga un impacto en el store
de origen.

En nuestro ejemplo, crearemos un store de origen y un store encadenado. También crearemos tres grids
simples que muestran los datos de estos stores. Nuestro ejemplo se verá a continuación.

Primero, cree el store para students que actuará como un store de origen como se muestra a continuación.
Ext.define('SchoolApp.store.Student', {
extend: 'Ext.data.Store',
model: 'SchoolApp.model.Student',

autoLoad: true,
sorters: [{
property: 'firstName',
direction: 'ASC'
}]

});

Ahora, cree un store encadenado llamado 'School App.store.Student Chained Store' en la misma carpeta que
se muestra a continuación.
Ext.define('SchoolApp.store.StudentChainedStore', {
extend: 'Ext.data.ChainedStore',
source:'SchoolApp.store.Student',
sorters: [{
property: 'firstName',
direction: 'desc'
}]

});

En el store encadenado anterior, observe que hemos especificado la configuración "fuente" que es
"SchoolApp.store.Student". Además, hemos especificado un sorter separado en el store encadenado. Ahora,
puede enlazar este store con el grid como de costumbre usando la configuración "store" del grid. Verá que el
grid que se adjunta al store encadenado muestra los datos en orden descendente, mientras que el grid con el
store principal muestra los datos en orden ascendente. Sin embargo, la edición de datos en cualquiera de los
grids afecta a todos los grids.
model\Student.js
Ext.define('SchoolApp.model.Student', {
extend: 'Ext.data.Model',
idProperty: 'Id',

schema: {
namespace: 'SchoolApp.model',
proxy: {
type:'ajax',
api: {
read: '/ExampleService.svc/students/'
},
reader:{
type:'json',
rootProperty:'data'
}
}
},
fields: [
{ name: 'Id', type: 'int' },
{ name: 'firstName', type: 'string' },
{ name: 'middleName', type: 'string' },
{ name: 'lastName', type: 'string' },
{ name: 'birthDate', type: 'date' },
{ name: 'address1', type: 'string' },
{ name: 'address2', type: 'string' },
{ name: 'city', type: 'string' },
{ name: 'state', type: 'string' }
]

});

Implementar CRUD en form Ext JS 6:


Aquí, aprenderá cómo implementar CRUD en la arquitectura Ext JS 6 MVVM.
Creamos nuestra primera aplicación Ext JS 6 en la sección de la aplicación First Ext JS. Continuaremos desde
allí y crearemos un formulario de ingreso de datos para los estudiantes con los botones Crear, Leer, Actualizar,
Eliminar, Restablecer y borrar que se verán a continuación.

Crear modelo:
Comencemos con el modelo primero. Cree el archivo Student.js en la carpeta app -> model y cree la clase
School.model.Student como se muestra a continuación.
Ext.define('School.model.Student', {

extend: 'Ext.data.Model',
idProperty:'Id',
schema: {
namespace: 'School.model'
},
fields: [
{ name: 'Id', type: 'int', defaultValue: 0},
{ name: 'firstName', type: 'string' },
{ name: 'middleName', type: 'string' },
{ name: 'lastName', type: 'string' },
{ name: 'birthDate', type: 'date' },
{ name: 'address1', type: 'string' },
{ name: 'address2', type: 'string' },
{ name: 'city', type: 'string' },
{ name: 'state', type: 'string' }
],

validations: [{
type: 'presence',
field: 'firstName'
}]

});

Crear View Form:


Ahora, vamos a crear un view Form utilizando el kit de herramientas classic de Ext JS 6. Entonces, cree la
carpeta student en la carpeta classic -> src -> view y luego agregue el archivo Student.js como se muestra a
continuación.
Ahora, cree una clase view form personalizada que derive de Ext.form.Panel con textfields y botones
necesarios como se muestra a continuación.
Ext.define('School.view.student.Student', {
extend: 'Ext.form.Panel',

xtype: 'studentForm',
title: 'Student Entry Form',

controller: 'student',
initComponent: function () {
Ext.apply(this,
{
// establezca jsonsubmit a true para la operación CUD usando form.Submit()
jsonSubmit: true,
url: '/api/student',
resizable: false,
collapsible: false,
bodyPadding: '5',
buttonAlign: 'center',
border: false,
trackResetOnLoad: true,
layout:
{
type: 'vbox'
},
fieldDefaults:
{
xtype: 'textfield',
msgTarget: 'side',
labelAlign: 'top',
labelStyle: 'font-weight:bold'
},
defaultType: 'textfield',
items: [{
xtype: 'fieldcontainer',
layout: 'hbox',
defaultType: 'textfield',
width: '100%',
fieldDefaults:
{
labelAlign: 'top',
labelStyle: 'font-weight:bold'
},
items: [{
fieldLabel: 'Id',
name: 'Id',
readOnly: true,
width: 55
},
{
fieldLabel: 'Nombre',
flex: 1,
name: 'firstName',
margin: '0 0 0 5',
allowBlank: false
},
{
name: 'middleName',
width: 150,
margin: '0 0 0 5',
fieldLabel: 'Sobrenombre:'
},
{
fieldLabel: 'Apellido',
flex: 1,
margin: '0 0 0 5',
name: 'lastName'
}]
},
{
xtype: 'datefield',
fieldLabel: 'Fecha de Nac.',
name: 'birthDate'
},
{
xtype: 'textfield',
fieldLabel: 'Dirección',
width: '100%',
name: 'address1'
},
{
xtype: 'textfield',
hideLabel: true,
name: 'address2',
width: '100%',
fieldLabel: 'Dirección 2'

},
{
xtype: 'textfield',
fieldLabel: 'Ciudad',
width: '100%',
name: 'city'
},
{
xtype: 'textfield',
fieldLabel: 'Estado',
width: '100%',
name: 'state'
}
],
buttons: [{
text: 'Crear',
itemId: 'btnCreate',
formBind: true,
handler: 'onCreateClick'
},
{
text: 'Leer',
itemId: 'btnLoad',
handler: 'onReadClick'
},

{
text: 'Editar',
itemId: 'btnUpdate',
formBind: true,
handler: 'onUpdateClick'
},
{
text: 'Borrar',
itemId: 'btnDelete',
formBind: true,
handler: 'onDeleteClick'
},
{
text: 'Revertir',
itemId: 'btnReset',
handler: 'onResetClick'
},
{
text: 'Limpiar',
itemId: 'btnClear',
handler: 'onClearClick'
}]
});

this.callParent(arguments);

},
clearForm: function () {
this.getForm().getFields().each(function (field) {
field.validateOnChange = false;
field.setValue('');
field.resetOriginalValue();
});
}
});

Crear ViewController:
Ahora, agregue la clase ViewController que maneja todos los eventos del view Student anterior. Cree
StudentController.js en la carpeta app -> view -> student como se muestra a continuación.
La clase ViewController de student debe derivar de Ext.app.ViewController. La siguiente es una clase Student
ViewController que maneja todos los eventos del view Student.
Ext.define('School.view.student.StudentController', {
extend: 'Ext.app.ViewController',

alias: 'controller.student',

onCreateClick: function (sender, record) {


var studentForm = this.getView().getForm();

if (!studentForm.isDirty()) {
Ext.Msg.alert('Status', ' No hay nuevos datos para crear.');
return;
}
else if (!studentForm.isValid()) {
Ext.Msg.alert('Status', 'Datos inválidos.');
return;
}

// Envia la solicitud de Ajax y maneja la respuesta.


studentForm.submit({
url: '/api/student',
waitMsg: 'Guardando..',
headers:
{
'Content-Type': 'application/json'
},
clientValidation: true,
submitEmptyText: true,
success: function (form, action) {

var student = Ext.create('School.model.Student');


var resp = Ext.decode(action.response.responseText);

if (resp.data[0]) {
// addstudent devuelve el modelo student con Id para que podamos volve
r a cargar el modelo en el form para que tenga isDirty false
student.set(resp.data[0]);
studentForm.loadRecord(student);
}

Ext.Msg.alert('Status', 'Guardado existosamente.');

},
failure: function (form, action) {
if (action.failureType === Ext.form.action.Action.CLIENT_INVALID) {
Ext.Msg.alert('CLIENT_INVALID', 'Algo se ha perdido. Por favor revisa
e intenta de nuevo.');
}
if (action.failureType === Ext.form.action.Action.CONNECT_FAILURE) {
Ext.Msg.alert('CONNECT_FAILURE', 'Status: ' + action.response.status +
': ' + action.response.statusText);
}
if (action.failureType === Ext.form.action.Action.SERVER_INVALID) {
Ext.Msg.alert('SERVER_INVALID', action.result.message);
}
}
});
},

onReadClick: function (sender, record) {


var studentForm = this.getView().getForm();

// el resultado debe contener success = true y la propiedad data, de lo contrario,


irá al error incluso si no hay un error
studentForm.load({
waitMsg: 'Cargando...',
method: 'GET',
params:
{
id: 1
},
success: function (form, action) {
try {
var resp = Ext.decode(action.response.responseText);

if (resp.data.length > 0) {
// addstudent devuelve el modelo student con Id para que podamos v
olver a cargar el modelo en el form para que tenga isDirty false
var student = Ext.create('School.model.Student');
student.set(resp.data[0]);
studentForm.loadRecord(student);
}
}
catch (ex) {
Ext.Msg.alert('Status', 'Exception: ' + ex.Message);

}
},
failure: function (form, action) {
Ext.Msg.alert("Carga fallida", action.result.errorMessage);
}
});
},

onUpdateClick: function (sender, record) {


var studentForm = this.getView().getForm();

if (!studentForm.isDirty()) {
Ext.Msg.alert('Status', 'No hay cambios pendientes para guardar.');
return;
}
else if (!studentForm.isValid()) {
Ext.Msg.alert('Status', 'Datos invalidos.');
return;
}
studentForm.submit({
url: '/api/student',
waitMsg: 'Actualizando..',
method: 'PUT',
headers:
{
'Content-Type': 'application/json'
},
clientValidation: true,
success: function (form, action) {
try {
var student = Ext.create('School.model.Student');
var resp = Ext.decode(action.response.responseText);

if (resp.data.length > 0) {
// addstudent devuelve el modelo student con Id para que podamos v
olver a cargar el modelo en el form para que tenga isDirty false
student.set(resp.data[0]);
studentForm.loadRecord(student);
}

Ext.Msg.alert('Status', 'Saved successfully.');


}
catch (ex) {
Ext.Msg.alert('Status', 'Exception: ' + ex.Message);

}
},
failure: function (form, action) {
if (action.failureType === Ext.form.action.Action.CLIENT_INVALID) {
Ext.Msg.alert('CLIENT_INVALID', 'Algo se ha perdido. Por favor revisa
e intenta de nuevo.');
}
if (action.failureType === Ext.form.action.Action.CONNECT_FAILURE) {
Ext.Msg.alert('CONNECT_FAILURE', 'Status: ' + action.response.status +
': ' + action.response.statusText);
}
if (action.failureType === Ext.form.action.Action.SERVER_INVALID) {
Ext.Msg.alert('SERVER_INVALID', action.result.message);
}
}
});
},
onDeleteClick: function (sender, record) {
var me = this,
studentForm = me.getView();

if (!studentForm.getValues(false, false, false, true).Id) {


Ext.Msg.alert('Status', 'No válido o no hay datos para eliminar.');
return;
}

var student = Ext.create('School.model.Student'), data;

student.set(studentForm.getValues());
data = student.getData();

Ext.Msg.show({
title: 'Borrar',
msg: '¿Quieres borrar este registro?',
width: 300,
closable: false,
buttons: Ext.Msg.YESNO,
icon: Ext.Msg.QUESTION,
fn: function (buttonValue, inputText, showConfig) {
if (buttonValue === 'yes') {
studentForm.submit({
url: '/api/student',
method: 'DELETE',
clientValidation: true,
waitMsg: 'Borrando..',
headers:
{
'Content-Type': 'application/json'
},

success: function (form, action) {


try {
var resp = Ext.decode(action.response.responseText);
studentForm.clearForm();

Ext.Msg.alert('Success', resp.message);
}
catch (ex) {
Ext.Msg.alert('Status', 'Exception: ' + ex.Message);

}
},
failure: function (form, action) {
if (action.failureType === Ext.form.action.Action.CLIENT_INVAL
ID) {
Ext.Msg.alert('CLIENT_INVALID', 'Algo se ha perdido. Por f
avor revisa e intenta de nuevo.');
}
if (action.failureType === Ext.form.action.Action.CONNECT_FAIL
URE) {
Ext.Msg.alert('CONNECT_FAILURE', 'Status: ' + action.respo
nse.status + ': ' + action.response.statusText);
}
if (action.failureType === Ext.form.action.Action.SERVER_INVAL
ID) {
Ext.Msg.alert('SERVER_INVALID', action.result.message);
}
}
});
}
}

});
},
onResetClick: function (sender, record) {
this.getView().getForm().reset();
},
onClearClick: function (sender, record) {
this.getView().clearForm();
},

});

Como puede ver en la clase controladora anterior, lee datos del servidor remoto usando el método form.load
() y realiza la operación CRUD usando el método form.submit (). Llama a api url/api/student para la operación
CRUD. (La url completa de la API Rest es http://localhost/api/student) Para cargar los datos, el método
form.load() envía la solicitud GET a la url /api/student. De la misma manera, form.submit() envía la solicitud
POST para crear un nuevo registro de student, la solicitud PUT para actualizar el registro y la solicitud DELETE
para eliminar el registro. Chequee el handler click de los botones Crear, Actualizar, Eliminar y Leer para saber
más.
Por lo tanto, puede implementar la operación CRUD en el formulario Ext JS. Haga clic en el Ejemplo en vivo a
continuación para ver el código de ejemplo completo en la estructura de carpetas MVVM.
CRUD en Grid Ext JS 6:
Aquí, aprenderá cómo implementar la operación CRUD en Ext JS 6
Creamos nuestra primera aplicación Ext JS 6 en la sección de la aplicación en First Ext JS. Aquí, continuaremos
y agregaremos el view grid para enumerar a todos los estudiantes con los botones Agregar y Eliminar que se
verán a continuación.
Crear modelo:
Comencemos con el modelo primero. Cree el archivo Student.js en la carpeta app -> model y cree la clase
School.model.Student como se muestra a continuación.

Ext.define('School.model.Student', {

extend: 'Ext.data.Model',
idProperty:'Id',
schema: {
namespace: 'School.model'
},
fields: [
{ name: 'Id', type: 'int', defaultValue: 0},
{ name: 'firstName', type: 'string' },
{ name: 'middleName', type: 'string' },
{ name: 'lastName', type: 'string' },
{ name: 'birthDate', type: 'date' },
{ name: 'address1', type: 'string' },
{ name: 'address2', type: 'string' },
{ name: 'city', type: 'string' },
{ name: 'state', type: 'string' }
],

validations: [{
type: 'presence',
field: 'firstName'
}]

});

Crear Grid View:


Ahora, vamos a crear un grid view usando el kit de herramientas clásico de Ext JS 6. Entonces, cree la carpeta
student en la carpeta classic -> src -> view y luego agregue el archivo StudentList.js como se muestra a
continuación.
En el archivo StudentList.js anterior, cree una grid view personalizado de StudentList derivado de Ext.grid.Panel
y defina columnas del grid como se muestra a continuación.
Ext.define('School.view.student.StudentList', {
extend: 'Ext.grid.Panel',
xtype: 'studentList',

title: 'Student List',

controller: 'student-list',
viewModel: { type: 'studentviewmodel' },
reference:'studentlistgrid',
selType: 'rowmodel',
selModel:
{
mode: 'SINGLE'
},
viewConfig:
{
stripeRows: true
},
listeners: {
selectionchange: 'onSelectionChange'
},
bind: {
store: '{StudentListStore}'
},
initComponent: function () {
Ext.apply(this,
{
plugins: [Ext.create('Ext.grid.plugin.RowEditing',
{
clicksToEdit: 2
})],

columns: [{
text: "Id",
dataIndex: 'Id',
hidden: false,
width: 35
},
{
text: "Nombre",
flex: 1,
dataIndex: 'firstName',
editor:
{
// por defecto es el textfield si no se proporciona xtype
allowBlank: false
}
},
{
text: "Sobre-nombre",
flex: 1,
dataIndex: 'middleName',
editor:
{
allowBlank: true
}
},
{
text: "Apellido",
flex: 1,
dataIndex: 'lastName',
editor:
{
allowBlank: true
}
},
{
xtype: 'datecolumn',
header: "Fecha Nac.",
width: 135,
dataIndex: 'birthDate',
editor:
{
xtype: 'datefield',
allowBlank: true
},
renderer: Ext.util.Format.dateRenderer('d/m/Y')
},
{
text: "Ciudad",
flex: 1,
dataIndex: 'city',
editor:
{
allowBlank: true
}
},
{
text: "Estado",
flex: 1,
dataIndex: 'state',
editor:
{
allowBlank: true
}
}],
tbar: [{
text: 'Agregar Estudiante',
iconCls: 'fa-plus',
handler: 'onAddClick'
}, {
itemId: 'removeStudent',
text: 'Quitar Estudiante',
iconCls: 'fa-times',
reference: 'btnRemoveStudent',
handler: 'onRemoveClick',
disabled: true
}]
});

this.callParent(arguments);
}
});

El grid anterior, incluye dos configs importantes el controller y el viewModel. La configuración del controller
especifica la clase controller para este grid view que manejará los eventos de esta vista. La configuración de
viewModel especifica la clase ViewModel que incluye el store para este grid.

Crear ViewModel:
Ahora, cree la clase StudentViewModel para el grid de la Lista de estudiantes en la carpeta app -> view ->
student como se muestra a continuación:

Ahora, defina la clase StudentViewModel como se muestra a continuación.


Ext.define('School.view.student.StudentViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.studentviewmodel',
stores: {
StudentListStore: {
model: 'School.model.Student',
autoLoad: true,
autoSync: true,
proxy:
{
type: 'rest',
reader:
{
rootProperty: 'data',
type: 'json'
},
url: '/api/student',
writer: {
type: 'json',
dateFormat: 'd/m/Y',
writeAllFields: true
}
}
}

}
});

Como puede ver, School.view.student.StudentViewModel incluye un store que estará vinculado al grid view.
Las configuraciones autoSync y autoLoad se configuran como verdaderas en StudentListStore para que el grid
muestre los datos tan pronto como cargue los registros y también actualizará o eliminará los registros una vez
que el usuario los modifique.

Crear ViewController:
Cree StudentViewController.js en la carpeta app -> view -> student.

Ahora, define la clase StudentViewController como se muestra a continuación:


Ext.define('School.view.student.StudentListController', {
extend: 'Ext.app.ViewController',

alias: 'controller.student-list',

onAddClick: function (sender, record) {

var studentGrid = this.getView();


var studentStore = studentGrid.getStore();

// añadiendo estudiante ficticio


var studentModel = Ext.create('School.model.Student');
studentModel.set("Id", 0);
studentModel.set("firstName", "New Student");
studentModel.set("middleName", "");
studentModel.set("lastName", "");
studentModel.set("birthDate", "");
studentModel.set("city", "");
studentModel.set("state", "");

studentStore.insert(0,studentModel);
},

onLoadClick: function (sender, record) {


var studentStore = this.getView().getStore();
studentStore.load();
},

onRemoveClick: function (sender, record) {


var studentGrid = this.getView();
var studentStore = studentGrid.getStore();

// eliminar filas seleccionadas si selModel es checkboxmodel


var selectedRows = studentGrid.getSelectionModel().getSelection();

studentStore.remove(selectedRows);
},

onSelectionChange: function (sender, record, isSelected) {


var removeBtn = this.lookupReference('btnRemoveStudent');
if(record.length)
removeBtn.setDisabled(false);
else
removeBtn.setDisabled(true);
}
});

Por lo tanto, puede implementar CRUD en grid en la arquitectura Ext JS 6 MVVM. Haga clic en el Ejemplo en
vivo a continuación para ver el código de ejemplo completo en la estructura de carpetas MVVM.

Sincronizar por lotes con Grid:


En el capítulo anterior, realizamos la operación CRUD en un solo registro. Aquí, aprenderemos cómo realizar
la operación CRUD en varios registros en una sola solicitud utilizando el método sync(), es decir, crear múltiples
registros en una sola solicitud o actualizar varios registros en una sola solicitud o eliminar varios registros en
una sola solicitud.

Nota: asegúrese de que su servicio acepte una matriz de objetos model como un parámetro de entrada porque
el método de sincronización enviará una matriz de objetos model como una carga útil de solicitud a la url
configurada.
Podemos llamar al método sync() de la misma manera que se vio en el capítulo anterior. Sin embargo, debemos
ser cuidadosos en el manejo de excepciones, como se muestra en el siguiente ejemplo:
// se disparan las solicitudes crear, actualizar y eliminar cuando se realizan sincronizacio
nes y se confirman los cambios en el store cuando autoSync = false
studentStore.sync({

success : function(batch, opt){


Ext.Msg.alert('Status', 'Los cambios se guardaron exitosamente.');
},
failure : function(batch, opt){
var msg = '';

if(batch.hasException){

for(var i = 0; i < batch.exceptions.length; i ++ ){


switch(batch.exceptions[i].action){
case "destroy":
msg = msg + batch.exceptions[i].records.length + " Delete,
";
break;
case "update" :
msg = msg + batch.exceptions[i].records.length + " Update,
";
break;
case "create" :
msg = msg + batch.exceptions[i].records.length + " Create,
";
break;
}
}

Ext.Msg.alert("Status", msg + " operation failed!");


}
else
Ext.Msg.alert('Status', 'Changes failed.');
}
});

Según el ejemplo anterior, verificamos si alguna operación ha fallado en un lote y mostramos el número de
operaciones fallidas de creación, actualización y eliminación.
controller\StudentMaster.js
Ext.define('School.controller.StudentMaster',
{
extend : 'Ext.app.Controller',
models : ['School.model.Student'],
stores : ['School.store.Student'],
views: ['School.view.StudentGrid'],

refs : [{
ref : 'studentGrid',
selector : 'viewport StudentGrid'
}],

init : function(){

this.control({
'viewport > StudentGrid button[itemId=btnSave]':
{
click : this.onSaveClick
},
'viewport > StudentGrid button[itemId=btnCreate]':
{
click : this.onCreateClick
},
'viewport > StudentGrid button[itemId=btnDelete]':
{
click : this.onDeleteClick
},
'viewport > StudentGrid button[itemId=btnLoad]' :
{
click : this.onLoadClick
}
});
},

onSaveClick : function(){

var studentGrid = this.getStudentGrid();


var studentStore = studentGrid.getStore(studentStore);

// se disparan las solicitudes crear, actualizar y eliminar cuando se realizan sincronizaci


ones y se confirman los cambios en el store cuando autoSync = falso
studentStore.sync({

success : function(batch, opt){


Ext.Msg.alert('Status', 'Changes saved successfully.');
},
failure : function(batch, opt){
var msg = '';

if(batch.hasException){

for(var i = 0; i < batch.exceptions.length; i ++ ){


switch(batch.exceptions[i].action){
case "destroy" :
msg = msg + batch.exceptions[i].records.length + " Delete, ";
break;
case "update" :
msg = msg + batch.exceptions[i].records.length + " Update, ";
break;
case "create" :
msg = msg + batch.exceptions[i].records.length + " Create, ";
break;
}
}

Ext.Msg.alert("Status", msg + " operation failed!");


}
else
Ext.Msg.alert('Status', 'Changes failed.');
}
});

},

onLoadClick : function(){

var studentStore = Ext.create('School.store.Student');


studentStore.load({
scope : this,
callback : function(records, operation, success){

var studentGrid = this.getStudentGrid();


studentGrid.bindStore(studentStore);
}
});

},
onCreateClick : function(){
var studentGrid = this.getStudentGrid();
var studentStore = studentGrid.getStore();

var studentModel = Ext.create('School.model.Student');


studentModel.set("firstName", "New student's first name");
studentModel.set("middleName", "New student's middle name");
studentModel.set("lastName", "New student's last name");
studentModel.set("birthDate", "11/01/2011");
studentModel.set("city", "New city");
studentModel.set("state", "New state");
studentStore.add(studentModel);

},
onDeleteClick : function(){

var studentGrid = this.getStudentGrid();


var studentStore = studentGrid.getStore();

var selectedRows = studentGrid.getSelectionModel().getSelection();


if(selectedRows.length)
studentStore.remove(selectedRows);
else
Ext.Msg.alert('Estado', 'Por favor, seleccione al menos un registro para eliminar!');
}
});

Paginación en Grid Ext JS:


Aquí, aprenderá cómo implementar la paginación del lado del servidor en un grid view en la arquitectura
MVVM. Vamos a construir una vista de la Lista de Estudiantes que se verá a continuación.

Necesitaríamos crear las siguientes clases para crear una demostración de paginación de cuadrícula como se
muestra arriba.
Model
ViewModel
View
Además, la implementación de la paginación del lado del servidor requiere la API REST u otro servicio web que
maneje la solicitud HTTP con parámetros de página (page), (start) inicio y (limit) límite. Hemos creado la
siguiente API web en .NET que maneja la solicitud HTTP GET.
public class StudentWebAPI
{
public StudentPage GetStudentPage(int page, int start, int limit)
{

StudentPage currentPage = new StudentPage();


var student = GetDataFromDatabase(); // Función de ejemplo que obtendrá los datos
de la db

currentPage.Students = students.Skip((page - 1) * limit).Take(limit).ToList<Studen


t>();

currentPage.TotalCount = students.Count;

return currentPage;

}
}

public class Student


{
public int Id { get; set; }

public string firstName { get; set; }

public string middleName { get; set; }

public string lastName { get; set; }

public string birthDate { get; set; }

public string address1 { get; set; }

public string address2 { get; set; }

public string city { get; set; }

public string state { get; set; }

}
public class StudentPage
{
public int TotalCount { get; set; }

public IList<Student> Students { get; set; }


}

Como puede ver en el ejemplo anterior, GetStudentPage manejará la solicitud GET de HTTP con los parametros
page, start y limit y devolverá una parte de los registros según estos parámetros. Enviará la clase StudentPage
como una respuesta que incluye las propiedades TotalCount y Students que se utilizarán para configurar la
paginación en Store ViewModel.

Crear modelo:
En primer lugar, vamos a crear una clase model para student. Cree Student.js en la carpeta app -> model y
defina la clase Student como se muestra a continuación.
Ext.define('School.model.Student', {

extend: 'Ext.data.Model',
idProperty:'Id',
schema: {
namespace: 'School.model'
},
fields: [
{ name: 'Id', type: 'int', defaultValue: 0},
{ name: 'firstName', type: 'string' },
{ name: 'middleName', type: 'string' },
{ name: 'lastName', type: 'string' },
{ name: 'birthDate', type: 'date' },
{ name: 'address1', type: 'string' },
{ name: 'address2', type: 'string' },
{ name: 'city', type: 'string' },
{ name: 'state', type: 'string' }
]

});

Crear ViewModel:
Después de crear la clase model, vamos a crear la clase ViewModel. Cree StudentViewModel.js en la carpeta
app -> view -> student y defina la clase StudentViewModel como se muestra a continuación.
Ext.define('School.view.student.StudentViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.studentviewmodel',
stores: {
StudentListPagingStore: {
model: 'School.model.Student',
autoLoad: true,
pageSize: 5,
proxy:
{
type: 'rest',
url: '/api/student'
reader:
{
type: 'json',
rootProperty: 'Students',
totalProperty: 'TotalCount'
}
}
}

}
});

En la clase ViewModel anterior, hemos definido StudentListPagingStore en config Store.


StudentListPagingStore utiliza el modelo School.model.Student que creamos anteriormente. La carga
automática (autoLoad) se establece en verdadero (true), lo que cargará datos cuando se cargue la vista. La
configuración de pageSize especifica la cantidad de registros que se mostrarán en un grid. La propiedad
rootProperty especifica el nombre de la propiedad en el JSON de respuesta que incluye datos. TotalProperty
especifica el nombre de la propiedad en los datos JSON de respuesta que indican el número total de registros
que es TotalCount en este caso porque nuestra API web devuelve respuesta con esta propiedad.

Crear vista (view):


Ahora, vamos a crear un componente grid view usando el kit de herramientas clásico. Cree StudentListPaging.js
en la carpeta classic -> src -> view -> student y defina el grid view StudentListPaging como se muestra a
continuación.
Ext.define('School.view.student.StudentListPaging', {
extend: 'Ext.grid.Panel',
xtype: 'studentListPaging',

title: 'Lista de estudiantes - Demostración de paginación',

viewModel: { type: 'studentviewmodel' },


selType: 'rowmodel',
selModel:
{
mode: 'SINGLE'
},
viewConfig:
{
stripeRows: true
},
listeners: {
selectionchange: 'onSelectionChange'
},
bind: {
store: '{StudentListPagingStore}'
},
initComponent: function () {
Ext.apply(this,
{
columns: [{
text: "Id",
dataIndex: 'Id',
width: 35
},
{
text: "Nombre",
flex: 1,
dataIndex: 'firstName'
},
{
text: "Sobrenombre",
flex: 1,
dataIndex: 'middleName'
},
{
text: "Apellido",
flex: 1,
dataIndex: 'lastName'
},
{
xtype: 'datecolumn',
header: "Fecha Nac.",
width: 135,
dataIndex: 'birthDate',
renderer: Ext.util.Format.dateRenderer('d/m/Y')
},
{
text: "Ciudad",
flex: 1,
dataIndex: 'city'
},
{
text: "Estado",
flex: 1,
dataIndex: 'state'
}],
bbar: [{
xtype: 'pagingtoolbar',
bind:{
store: '{StudentListPagingStore}'
},
displayInfo: true,
displayMsg: 'Mostrando {0} a {1} de {2} &nbsp;records ',
emptyMsg: "Sin registros para mostrar&nbsp;"
}]

});

this.callParent(arguments);
}
});

En la grid view anterior, hemos usado pagingtoolbar en la barra inferior. Esta es la barra de herramientas de
paginación que muestra los botones: siguiente, anterior, primero y último con información de paginación.
Puede configurar esto según su necesidad. Visite Sencha docs para obtener más información sobre la barra de
herramientas de paginación.
Por lo tanto, puede implementar la paginación del lado del servidor en el componente Ext JS Grid. Haga clic en
el Ejemplo en vivo a continuación para ver el código de ejemplo completo en la estructura de carpetas MVVM.

Das könnte Ihnen auch gefallen