Pasar valor de un grid para query en un 2º grid
Buenas a todos, este es mi primer post. Quiero decir que lo primero que aprendí (lo unico en realidad) fue por los videotutoriales de este sitio web. Tengo conocimientos en php y sql, recien me meto en js.
Estoy empezando con una app que en principio carga un grid con datos que tengo en SQL Server 2008. Lo que quiero poder hacer, es que cuando toco en algunas de las filas del grid (con usuarios) me de un valor para poder cargar otros datos de otra tabla referidos al usuario que seleccione.
Para resumir, quiero tener un Grid arriba de usuarios y abajo de movimientos de esos usuarios. Al tocar un usuario ver los detalles de esos movimientos. Estos datos los tengo almacenados en tablas diferentes.
Estoy trabajando con ExtDesigner y toco un poco de codigo tabien, los datos los paso a JSON y los cargo en el store con un php. Pienso que para hacer lo que quiero, tendria que dejar la consulta sql en condicional (con un if en php) y al enviar algun valor haga la segunda consulta.
Espero que se entienda, jeje, y puedan darme una mano.
Saludos.
Lo revivo porque me parece que hice mal en seguir este post... debí haber hecho uno nuevo...
Se apreciará ayuda.
Ahora me esta surgiendo algo mas complejo. Tengo una app (adjunto imagen) que basicamente tiene un panel norte general (donde elijo el empleado que quiero ver) y otro panel center con detalles de los movimientos en la fabrica (ausencias, sanciones, etc) en el panel center tengo un panel expandible tambien en east, que muetra detalles mas profundos por si se necesitan junto con la foto. Para cargar ese panel use el metodo rowselect y update que propone el ejemplo de extdisigner (el del video de los detalles de los autos) en la pagina de sencha. Ahora pongo mi codigo y sigo.
MyPanel = Ext.extend(MyPanelUi, {
initComponent: function() {
MyPanel.superclass.initComponent.call(this);
this.legajos.on('rowclick',this.leer_justif,this);
this.legajos.on('rowclick',this.leer_resumen,this);
this.legajos.on('rowclick',this.leer_resumenanio,this);
this.legajos.on('rowclick',this.leer_ausencias,this);
this.legajos.on('rowclick',this.leer_sanciones,this);
var sm = this.legajos.getSelectionModel();
sm.on('rowselect', this.onGridRowSelect, this);
},
onGridRowSelect: function(sm, rowIdx, r){
this.detalles.update(r.data)
},
leer_justif: function(grid,index) {
this.justif.getStore().baseParams.Legajo=grid.getStore().getAt(index).get('Legajo');
this.justif.getStore().load();
},
leer_resumen: function(grid,index) {
this.resumen.getStore().baseParams.Legajo=grid.getStore().getAt(index).get('Legajo');
this.resumen.getStore().load();
},
leer_resumenanio: function(grid,index) {
this.resumenanio.getStore().baseParams.Legajo=grid.getStore().getAt(index).get('Legajo');
this.resumenanio.getStore().load();
},
leer_ausencias: function(grid,index) {
this.ausencias.getStore().baseParams.Legajo=grid.getStore().getAt(index).get('Legajo');
this.ausencias.getStore().load();
},
leer_sanciones: function(grid,index) {
this.sanciones.getStore().baseParams.Legajo=grid.getStore().getAt(index).get('Legajo');
this.sanciones.getStore().load();
}
});
Lo que ahogo aca es pasarle los valores tel store general para no cargar otro store mas con los ismos datos, pero tengo un problema: rowselect me cambia los datos al hacer click o al mover con las flechas del teclado... rowclick me cambia SOLO al hacer click. Entonces si el operador cambia de registro con el teclado, parte delos datos de van a actualizar y otra parte no, dejando discrepancia entre los datos del empleado y los movimientos.
Lo que necesito es hacer que todo funcione con rowselect o rowclick, pero ambos de la misma manera. Obviamente cambie rowclick por rowselect y viceversa pero uno de los dos SIEMPRE deja de actualizar.
Adjunto una imagen y espero que por favor alguien me de una mano.
Saludos.
listeners:{'rowclick':leer_detalle: function(grid,index) {
var st = this.grid_detalle.getStore();
el error está en que aunque tu grid tenga como referencia grid_detalle, desde esta parte del código no puede leer ese componente, por eso puedes usar la propiedad storeId del store para obtener el store, agregarle el scope: this a tu funcion, o puedes - si le asignas un id a tu grilla - obtenerlo por:
Ext.getCmp('id_de_mi_grilla').getStore();
pero esto es poco eficiente, aunque cuando no hay otra forma hay que echar mano a lo que funciona. :)
Yo estoy enviando un id desde un grid a otro dentro de un tabpanel, con el ejemplo tal cual me mostro tokkaido... Yo tuve problemas con las referencias pero lo arregle, primero me aseguré que en POST aparezca el valor, despues me encargue de agarrarlo como variable para la segunda consulta a SQL...
Gracias por la pronta respuesta @Gustavo21 y entiendo muy bien lo que @Tokkaido te indico y creeme tambien fue de gran ayuda para mi, lo que pasa es que segun el ejemplo de @Tokkaido crean un archivo app.ui.js y otro app.js que es un extend del primero y en html dentro de divs y scripts crean una var que crea la ventana con los grids integrados y se que funciona lo probe en local y funciona, pero yo tengo mi viewport y dentro de este un tabpanel, dentro del tabpanel creo dos grillas, mi idea es que en la grilla principal creo un listener de esta forma...
listeners:{'rowclick':leer_detalle: function(grid,index) {
var st = this.grid_detalle.getStore();
st.baseParams.id_grupo = grid.getStore().getAt(index).get('cod_grupo');
st.load();
} }
pero al darle clic a una fila de grilla principal la consola arroja el error de has no method 'getStore'....tal vez en tu proyecto funciona porque creeria que dentro del tab llamas a toda la div o un html con el contenido de este post en autoload del tab, pero en mi proyecto los items del tab son dos grids...espero me haga entender y me puedas ayudar....gracias
tengo un problema con la gran ayuda que @Tokkaido y @Gustavo21 han brindado a mi proyecto, pero la funcion que utilizan para enviar el ID de una grid al otro, al tratar de implemenatarla dentro de un listener en un grid que esta dentro de un tabpanel y que su objetivo es el mismo que actualize un segundo grid, ya cree el listener y agrego la funcion que esta pregunta @Tokkaido propuso a @Gustavo21, pero en la consola de errores de Chrome me sale has no method 'getStore' y no entiedo porque agradezco cualquier ayuda....aqui el codigo....
new Ext.TabPanel({
region: 'center', // a center region is ALWAYS required for border layout
deferredRender: false,
activeTab: 0,
margins:'5 5 5 5', // first tab initially active
items: [{
title: 'Formulas',
iconCls: 'formulas',
closable: true,
items:[{
xtype: 'grid',
height:350,
plugins: [expander/*,editor*/],
//width:600,
style:'padding:5px 5px 5px 5px',
title: 'Formulas Existentes',
store: 'st_grupo',
tools: tools,
collapsible: true,
collapsed: false,
//flex: 1,
id: 'grid_grupo',
ref: 'grid_grupo',
listeners:{'rowclick': function (grid_grupo,index, e)
{ var st = grid_detalle.getStore();
st.baseParams.id_grupo = grid_grupo.getStore().getAt(index).get('cod_grupo'); st.load();
}
},
selModel: new Ext.grid.RowSelectionModel({
singleSelect: true,
moveEditorOnEnter: false,
}),
columns: [
expander,
new Ext.grid.RowNumberer(),
{
xtype: 'gridcolumn',
header: 'COD',
dataIndex: 'cod_grupo',
sortable: true,
width: 70
},
{
xtype: 'gridcolumn',
header: 'Marca',
dataIndex: 'marca',
sortable: true,
width: 70
},
{
xtype: 'gridcolumn',
header: 'Tipo',
dataIndex: 'tipo',
sortable: true,
width: 70
},
{
xtype: 'gridcolumn',
header: 'Modelo',
dataIndex: 'modelo',
sortable: true,
width: 150
},
{
xtype: 'gridcolumn',
header: 'Opciones',
dataIndex: '',
sortable: true,
width: 150
}
],
},
{
xtype: 'grid',
height:420,
style:'padding:5px 5px 5px 5px',
title: 'Detalle Formula',
store: 'st_detalle',
tools: tools,
collapsible: true,
collapsed: false,
//flex: 1,
id: 'grid_detalle',
ref: 'grid_detalle',
selModel: new Ext.grid.RowSelectionModel({
singleSelect: true,
moveEditorOnEnter: false
}),
columns: [
new Ext.grid.RowNumberer(),
{
xtype: 'gridcolumn',
header: 'Cant.',
dataIndex: 'cantidad',
sortable: true,
width: 40
},
{
xtype: 'gridcolumn',
header: 'Referencia',
dataIndex: 'referencia',
sortable: true,
width: 150
}
,
{
xtype: 'gridcolumn',
header: 'Ref. Alterna',
dataIndex: 'alterna',
sortable: true,
width: 150
} ,
{
xtype: 'gridcolumn',
header: 'Descripcion',
dataIndex: 'nom',
sortable: true,
width: 200
},
{
xtype: 'gridcolumn',
header: 'V. Unitario',
dataIndex: 'valor',
sortable: true,
width: 100
},
{
xtype: 'gridcolumn',
header: 'V. Total',
dataIndex: 'total',
sortable: true,
width: 100
},
{
xtype: 'gridcolumn',
header: 'B. Sexta',
dataIndex: 'sexta',
sortable: true,
width: 100
},
{
xtype: 'gridcolumn',
header: 'B. Salitre',
dataIndex: 'salitre',
sortable: true,
width: 100
},
{
xtype: 'gridcolumn',
header: 'B. Bquilla',
dataIndex: 'bquilla',
sortable: true,
width: 100
}
]
}]
}]
})]
}
GRACIAS!!!!!!!!!!! Ya esta andando! el unico problema que tengo, es que el paginado del segundo grid no funciona, ya que al hacer click en "siguiente" me anvia valores post solo de limit y start... no me envia el valor que necesito para filtrar el query, por lo tanto la segunda pagina me aparece en blanco...
Mientras tanto voy a seguir trabajando en otro panel que me muestre los datos mas profundos del usuario del primer grid...
Saludos.
cambia la función leer_detalle:
leer_detalle: function(grid,index) {
var st = this.grid_detalle.getStore();
st.baseParams.id_usuario = grid.getStore().getAt(index).get('id_usuario');
st.load();
}
debería funcionarte, lo que pasa es que "params" se envía solo una vez, en cambio baseParams se envía cada vez que hace load() o reload()
Suerte
tranquilo Gustavo, nadie nace sabiendo y hasta hace poco yo también era un completo novato, ahora conozco un poco mas de esta herramienta pero en este foro y otros que he participado siempre hay gente con buena voluntad que les gusta ayudar a sus pares.
Te voy a mostrar un poco como debería ser tu estructura para ver si se te aclara la película mira que una de mis mayores frustraciones en este lenguaje al principio fue "donde coloco el código?"
por una lado tienes tu definición de componente en un archivo llamado digamos myVentana.ui.js que podría ser asi:
myVentanaUi = Ext.extend(Ext.Window, {
title: 'Mi ventana',
width: 819,
height: 482,
layout: 'hbox',
initComponent: function() {
this.layoutConfig = {
align: 'stretch'
};
this.items = [
{
xtype: 'grid',
title: 'Usuarios',
store: 'st_usuarios',
flex: 1,
ref: 'grid_usuarios',
selModel: new Ext.grid.RowSelectionModel({
singleSelect: true,
moveEditorOnEnter: false
}),
columns: [
{
xtype: 'gridcolumn',
header: 'Nombre y apellido',
dataIndex: 'nombre',
sortable: true,
width: 190
},
{
xtype: 'gridcolumn',
header: 'Usuario',
dataIndex: 'usuario',
sortable: true,
width: 100
},
{
xtype: 'gridcolumn',
header: 'Clave',
dataIndex: 'clave',
sortable: true,
width: 100
}
]
},
{
xtype: 'grid',
title: 'Datos de los usuarios',
store: 'st_datos',
flex: 1,
ref: 'grid_detalle',
selModel: new Ext.grid.RowSelectionModel({
singleSelect: true,
moveEditorOnEnter: false
}),
columns: [
{
xtype: 'datecolumn',
header: 'Fecha de la conexion',
dataIndex: 'fecha_conexion',
sortable: true,
width: 220
},
{
xtype: 'gridcolumn',
header: 'Accion realizada',
dataIndex: 'accion',
sortable: true,
width: 100
}
]
}
];
myVentanaUi.superclass.initComponent.call(this);
}
});
por otro lado tenemos la parte que manejara los eventos que realicemos en dicha ventana, por estándar myVentana.js
myVentana = Ext.extend(myVentanaUi, {
initComponent: function() {
myVentana.superclass.initComponent.call(this);
//IMPORTANTE: aqui van todos los 'listener' que manejan la interface
//los clic a botones, cuando se carga la ventana, etc
this.grid_usuarios.on('rowclick',this.leer_detalle,this);
},
//de aqui hacia abajo todas las funciones que se gatillan cuando los eventos
//son disparados
leer_detalle: function(grid,index) {
this.grid_detalle.getStore().load({
params: {
//aquí puedes pasar los parámetros que quieras recibir al lado del php
id_usuario:grid.getStore().getAt(index).get('id_usuario')
}
}, this);
}
});
ademas tendremos la definición de los 2 stores de nuestras grillas. EL store de lo usuarios st_usuarios.js
st_usuarios = Ext.extend(Ext.data.JsonStore, {
constructor: function(cfg) {
cfg = cfg || {};
st_usuarios.superclass.constructor.call(this, Ext.apply({
storeId: 'st_usuarios',
root: 'data',
url: 'st_usuarios.php',
autoLoad: true,
fields: [
{
name: 'nombre'
},
{
name: 'usuario'
},
{
name: 'clave'
},
{
name: 'id_usuario'
}
]
}, cfg));
}
});
new st_usuarios();
y el de los datos st_datos.js
st_datos = Ext.extend(Ext.data.JsonStore, {
constructor: function(cfg) {
cfg = cfg || {};
st_datos.superclass.constructor.call(this, Ext.apply({
storeId: 'st_datos',
root: 'data',
url: 'st_datos.php',
fields: [
{
name: 'id_dato'
},
{
name: 'fecha_conexion',
type: 'date'
},
{
name: 'accion'
}
]
}, cfg));
}
});
new st_datos();
luego tienes tu html que empaqueta todos los archivos:
Grids on cascade
ademas necesitaremos los php que manejaran los datos, en mi caso con MySql:
st_usuarios.php
y el de los datos st_datos.php
en estricto rigor podrías poner todo en un solo archivo o mezclar algunos, pero para empezar por un tema de claridad te recomiendo trabajar así, incluso tengo todos mis archivos separados en carpetas de tal forma que cuando tienes una aplicación con 50 módulos o más es mas sencillo encontrar el código, un par de recomendaciones de un exnovato:
*desde un principio establece estándares a la hora de nombrar tus componentes.
*trata de evitar el uso de "id", y manéjate mas con "ref" para referirte a los componentes y "name" para los submits.
*profundiza en el concepto de ajax, muchos componentes se basan en ajax , como los submit(), load(), etc, y todos tienen sus callback para manejar código cuando estén cargadas porque debes recordar (y te evitara muchos dolores de cabeza) que el ajax es ASINCRONICO, lo que quiere decir que la ejecución de tu código no se detendrá a esperar que se devuelva el dato, se cargue el store, etc.
*sobre lo mismo, si en un combobox se te carga el "id" del elemento y no su nombre en el 99,9% de los casos es que estas asignándole el valor cuando el store aun no está cargado.
*y aunque cansador cuando te lo dicen al principio (a mi me molestaba mucho) LEE LA API, en verdad contiene mucha información útil.
espero haberte ayudado ;)
Ahora veo que el Ext designer tiene una opcion que dice "promote to class" es por eso que mis archivos js no tienen la misma estructura no? A que objetos debería cambairlos a clase? ventana, grid, panel? o estaré hablando pavadas... Se que nadie quiere perder tiempo con un novato, pero no encuentro lugar donde se explique como empezar con extjs aparte de este sitio web. Estoy totalmente perdido, no se por donde arrancar, despues seguramente voy a terminar haciendo algo bueno... es mas, yo despues de aprender php hice un blog de php con DW con videotutoriales... soy una persona que devuelve los conocimientos adquiridos.
Gracias.
es muy sencillo, si estas usando el modelo de trabajo del ExtDesigner deberias poder hacerlo asi:
creas un listener al evento rowselect de tu primera grid asi:
this.grid_usuarios.on('rowclick',this.leer_detalle,this);
grid_usuarios es el ref que asignaste a tu grid
en la función colocas lo siguiente:
leer_detalle: function(grid,index) {
this.grid_detalle.getStore().baseParams.id=grid.getStore().getAt(index).get('id_usuario');
this.grid_detalle.getStore().load();
}
en esta parte el grid_detalle es el ref de tu gris donde quieres cargar lso datos del usuario
id_usuario sera el valor que tengas en tu store de usuarios para determinar el usuario
esta parte de la carga la puedes hacer de varias formas en todo caso, podria hacerlo asi:
Ext.StoreMgr.lookup('el_storeId_de_tu_store_detalle').load({
params: {
id: grid.getStore().getAt(index).get('id_usuario')
})
de las dos formas envias por POST el id que leugo en tu php deberas capturar asi:
$id = $_POST['id'];
$sql_query = "SELECT * FROM mi_tabla_detalle WHERE id_usuario = $id";
y ejecutar tu consulta, imagino que usaras un mismo archivo php para las 2 cargas por lo que deberias modificar lo que he puesto arriba asi:
Ext.StoreMgr.lookup('el_storeId_de_tu_store_detalle').load({
params: {
id: grid.getStore().getAt(index).get('id_usuario'),
operacion: 'detalle'
})
y donde haces la carga de tu store usuarios lo siguiente:
Ext.StoreMgr.lookup('el_storeId_de_tu_store_usuarios').load({
params: {
operacion: 'usuarios'
})
ya en tu php podrias colocar lo que sigue
$operacion = $_POST['operacion'];
switch ($operacion){
case "usuarios" :
usuarios();
break;
case "detalle"
detalle();
break;
}
function usuarios(){
//todo tu codigo de consulta a tu bd
}
function detalle(){
$id = $_POST['id'];
$sql_query = "SELECT * FROM mi_tabla_detalle WHERE id_usuario = $id";
}
espero te sirva :)
Muchas Gracias!! no pude probarlo, pero mañana en el trabajo me fijo... por ahora te comento que es entendible y sencillo, no puedo esperar a tener la "facilidad" para escribir el código ya que con extdesigner no se puede hacer todo... lo mismo me pasaba en php y ya uso mas el codigo que lo visual.
Cualquier duda que tengo aviso, a lo mejor voy a tener alguna duda de donde poner alguna de las funciones...
Saludos.
te comento que comencé a usar la forma que propone ExtDesigner para trabajar y la verdad es que me ha ayudado un montón a separar las interfaces del manejo de eventos de mis aplicaciones, así que incluso cuando no uso ExtDesigner sigo manteniendo esa estructura.
Uh... no pude hacerlo andar... no encuentro donde tengo que poner el codigo... estoy mas lejos de lo que pensaba.
Esta es mi ventana:
MyWindowUi = Ext.extend(Ext.Window, {
title: 'My Window',
width: 1324,
height: 856,
constrain: true,
maximizable: true,
initComponent: function() {
this.items = [
{
xtype: 'panel',
height: 476,
items: [
{
xtype: 'grid',
store: 'ConsStore',
height: 475,
ref: 'legajos',
selModel: new Ext.grid.RowSelectionModel({
}),
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'Legajo',
header: 'Legajo',
sortable: true,
width: 100
},
{
xtype: 'gridcolumn',
dataIndex: 'Nombre',
header: 'Apellido, Nombres',
sortable: true,
width: 200,
align: 'left'
},
{
xtype: 'gridcolumn',
dataIndex: 'DesDpto',
header: 'Departamento',
sortable: true,
width: 300
},
{
xtype: 'gridcolumn',
dataIndex: 'FecIng',
header: 'Fecha Ing.',
sortable: true,
width: 100
}
],
bbar: {
xtype: 'paging',
store: 'ConsStore'
}
}
]
}
];
MyWindowUi.superclass.initComponent.call(this);
}
});
Lo del query y datos en json me las arreglo... creo. Trate de poner el listener y la funcion pero simpre me dice "this.legajos is undefined" legajos es el autoref del grid
a ver, primero esta es tu definición de la interface de tu ventana, el código que te puse debe estar en el archivo donde manejas los eventos de tu ventana, me explico:
tu tienes MyWindowUi que es la definición de tu interface, luego esta ventana es instanciada dentro de otro archivo o en otra parte de tu archivo (obviamente de forma posterior a la definición) donde colocas los eventos de tu ventana si es que trabajas con la forma que usa Ext.Designer.
para poder ayudarte mejor debes colocar todo el código relacionado para decirte donde debes colocar estas funciones
Bueno, pongo el code del resto de los archivos, menos los php que son de los stores:
- windowui.js es el que esta arriba
Window.js
WindowPers = Ext.extend(WindowPersUi, {
initComponent: function() {
WindowPers.superclass.initComponent.call(this);
}
});
xds_index.js
Ext.onReady(function() {
Ext.QuickTips.init();
var cmp1 = new WindowPers({
renderTo: Ext.getBody()
});
cmp1.show();
});
El js de un store:
ConsStore = Ext.extend(Ext.data.JsonStore, {
constructor: function(cfg) {
cfg = cfg || {};
ConsStore.superclass.constructor.call(this, Ext.apply({
storeId: 'ConsStore',
root: 'root',
url: 'data.php',
totalProperty: 'records',
autoLoad: true,
fields: [
{
name: 'Legajo'
},
{
name: 'Nombre'
},
{
name: 'DesDpto'
},
{
name: 'FecIng'
}
]
}, cfg));
}
});
new ConsStore();
Despues me quedan los php y los html que creo que no son relevantes.
Mil gracias por la ayuda.
Saludos.
Hola soy nuevo en esto de Extjs, estoy haciendo algo similar a lo tuyo para un proyecto, he probado los códigos que pone Tokkaido pero no puedo hacerlos funcionar.
Estoy programando todo a puro código sin ExtDesigner.
Espero me puedan ayudar
:(
¿Conoces a alguien que pueda responder esta pregunta? Comparte el link en Twitter o Facebook
Es necesario registrarse para poder participar en el foro! Si ya tienes una cuenta puedes entrar y comentar en este foro.