initComponent: Как получить данные родителя и как получить store для вызова load()?
Всем привет.
Есть форма, внутри которой моя таблица. Нужно при открытии формы загрузить данные в таблицу с сервера. Единственное до чего додумался это использовать initComponent в моей таблице. Таблица как бы независимая и имеет свой контролер. Но не знаю как получить Id родителя (формы), при том не тот что генерируется ExtJS, а с сервера, т.е. ИД из данных в форме. Пробую, получить, вызывая this.findParentByType('orderEdit').getViewModel().data.singleOrderно получаю значение по умолчанию, оно у меня null, получается родительская форма не получила ещё свои данные на момент создания таблицы. Как правильно это сделать, может как-то по другому данные родителя получать? Помимо этого надо чтобы таблица загрузила с сервера данные, вроде надо вызвать store.load() таблицы, но стор таблицы тоже получить не могу, пишет что он пустой, типа вообще не определен. Как бы выходит что и стор тоже ещё не подсоединился к моей таблицы. (У формы свой стор, у таблицы свой.) Как всё это дело получить? Может быть это надо делать в другом месте, а не в initComponent? |
в javascript в целом и в extjs в частности сломать всё можно миллионом способов. нужен тест кейс
|
Тут по моему не то что сломано, а просто наверное что-то не правильно делаю или вообще такое не предусмотрено.
Попробую сформулировать один из вопросов по другому. Если я в store устанавливаю autoLoad: false то как при показе таблицы мне загрузить в неё данные? Т.е. автозагрузка отключена и значит таблица будет пустая. В какой момент и где мне вызвать функцию store.load()? |
может быть вызвать store.load() в обработчике события afterrender вашей таблицы. Обработчик можно определить в том числе и внутри initComponent:
this.listeners = { afterrender: function(grid) { grid.getStore().load(); } } Гадать, не хочется. Выложите кусок кода хотя бы... |
Кажется нашел как решить проблему загрузки таблицы без автозагрузки. Но очень удивлен тем как это сделано. Я почему-то думал, если определил модель, стор и view, то всё автоматом создастся и свяжется между собой. а как видно из куска кода ниже, ничего подобного. Без автозагрузки в сторе, стор надо создавать самому и явно, а не пытаться к нему обратиться. Как-то не очевидно для меня.
Ext.define('JournalApp.view.notes.Note', { extend: 'Ext.grid.Panel', //'Ext.panel.Panel',// noteStore: null, initComponent: function() { this.callParent(); this.noteStore = Ext.getStore('JournalApp.store.NoteStore'); this.on('render', this.loadStore, this); }, loadStore: function() { this.noteStore.load({ scope: this, params: { orderid: 'тут ид родителя таблицы, но как получить?' } }); }, Если это так, то данные из родительского контейнера не получить, если не создать их самому явно, но они существуют. Ума не приложу как теперь получить данные из контейнера, содержащего мою таблицу. |
Я пробовал через это событие (похоже я его угадал, если вы предложили:) ), но там тоже при вызове load() пишет ошибку. Но кажется данный кусок проблемы решился, но как-то неожиданным образом, как в вашем примере для меня было бы логичней.
Теперь надо получить данные из контейнера, содержащего эту таблицу. Пробую это делать в той же функции initComponent, но там все данные пустые, а мне всего лишь нужен Id, но не служебный, а тот что с сервера был получен. Я выше выложил кусок кода и по сути у меня это всё что относиться к данной проблеме. Если нужно я конечно могу выложить весь код, но там большие портянки и даже не знаю, что именно из этого поможет решить проблему. Может быть к тому что в посте выше ещё можно показать какая у меня иерархия компонентов. Вот так я определил форму и в ней мою таблицу, initComponent из которой я привел выше. (Убрал что явно я думаю не по делу, типа заголовка формы, другие поля и т.п.) Ext.define('JournalApp.view.orders.OrderEdit', { extend: 'Ext.form.Panel', xtype: 'orderEdit', requires: [ 'JournalApp.view.orders.OrderViewModel', 'JournalApp.view.notes.Note', ], controller: 'orders', viewModel: { type: 'order' }, items: [{ xtype: 'noteGrid', fieldLabel: 'Заметки:', viewModel: { type: 'order' }, bind: { store: '{notes}' }, }] }); Цитата:
|
Ext.define('JournalApp.view.notes.Note', { extend: 'Ext.grid.Panel', //'Ext.panel.Panel',// alias: 'widget.myGrid', // <-- подобным образом напишите в родительской форме widget.myForm noteStore: null, initComponent: function() { this.callParent(); this.noteStore = Ext.getStore('JournalApp.store.NoteStore'); this.on('render', this.loadStore, this); }, loadStore: function(grid) { var formId = grid.up('myForm').getViewModel().data.singleOrder; // <-- ищем форму по alias myForm this.noteStore.load({ scope: this, params: { orderid: formId } }); }, |
хранилище грида можно назначать и во ViewModel, если мне не изменяет память. Там есть спецпараметр stores.
|
Вложений: 1
К сожалению это не помогло. Возвращает значение, которое у меня указано по умолчанию. Оно при открытии формы заменяется на текущее. Получается данные ещё не загрузились в форму, ну как я думаю.
Вот так выглядит моя ViewModel: Ext.define('JournalApp.view.orders.OrderViewModel', { extend: 'Ext.app.ViewModel', alias: 'viewmodel.order', requires: [ 'JournalApp.model.OrderModel', 'JournalApp.store.NoteStore' ], data: { name: 'Разделы', singleOrder: null // <--- ВОЗВРАЩАЕТ ВОТ ЭТОТ NULL ВМЕСТО ДАННЫХ }, stores: { orders: { model: 'OrderModel', autoLoad: true, autoSync: true, sorters: [{ property: 'createddate', direction: 'DESC' }], proxy: { type: 'rest', url : 'journal/orders/', //pageParam: '', //startParam: '', //limitParam: '', reader: { type: 'json', rootProperty: 'orders' }, writer: { type: 'json', writeAllFields: true, // это чтобы все поля передавать на сервер. allDataOptions: { associated: true // <- THE MOST IMPORTANT CHANGE (С этим стал передвать вложенные модели) }, } } }, strategys: { source: 'JournalApp.store.StrategyStore', }, notes: { source: 'JournalApp.store.NoteStore', } } }); Форма у меня создается в закладке Tab и ей присваиваются данные, которые я передаю из строки главной таблицы, не той о которой сейчас идет разговор, а другая. Вот такой строкой я присваиваю данные: orderTab.getViewModel().setData({ singleOrder: record }); И они присваиваются, их даже видно в переменной formId из вашего примера, если вызвать console.log(formId), но только в момент выполнения там null, а не данные. Я пытался делать через grid.findParentByType('orderEdit').getViewModel(). data.singleOrder , но там то же самое, в момент вызова null, а в консоли потом есть все данные. Вот так вызвал логи и прикрепил картинку, того как это выглядит в итоге: var formId = grid.up('orderEdit').getViewModel().data.singleOrder; console.log('formId', formId); console.log('data', grid.up('orderEdit').getViewModel().data); Цитата:
|
Правильно ли я понимаю, что при клике по узлу "Ордера" в левом дереве в правой части появляется панель с одной закладкой, которая содержит таблицу со всеми ордерами, и под ней таблица со всеми заметками. Потом при клике на отдельный ордер в общем списке проявляется сбоку от него форма с данными ордера, а нижняя панель заметок фильтруется под выбранный ордер.
Если так, то после клика по строке ордера при создании нового экземпляра формы можно назначить ссылку на выбранную запись во ViewModel через links или linkTo. У таблицы заметок есть своё хранилище. На мой взгляд, лучше найти этот компонет при помощи up() и down(), затем извлечь его хранилище через getStore() и выполнить фильтрацию filter(), указав в фильтре id выбранного ордера. Благо в обработчике события selectionchange, выполняющем всю эту логику есть информация о выбранной строке. Поправьте, если я чего недопонял в задаче. |
Этот код выглядит странно. Много чего лишнего.
Ext.define('JournalApp.view.notes.Note', { extend: 'Ext.grid.Panel', //'Ext.panel.Panel',// noteStore: null, initComponent: function() { this.callParent(); this.noteStore = Ext.getStore('JournalApp.store.NoteStore'); this.on('render', this.loadStore, this); }, loadStore: function() { this.noteStore.load({ scope: this, params: { orderid: 'тут ид родителя таблицы, но как получить?' } }); }, Запись noteStore: null, не нужна, так как в гриде и так есть store. Незачем делать дубликат. Запись this.noteStore = Ext.getStore('JournalApp.store.NoteStore'); вообще не нужна. Все работает и без нее. Нужно store задавать как и полагается: store: {type: "алиас сторе"} Запись this.on('render', this.loadStore, this); не нужна, можно просто store сделать autoload Проблема " ид родителя таблицы, но как получить?" не решаемая, ибо не виден контекст использования этого кода. Нужна песочница. Сделай те пример. |
Цитата:
|
Сначала всё правильно, когда кликаем по "ордерам" в левой части, то открывается закладка "Ордера", где находится перечень всех ордеров в виде таблицы, но там только таблица с ордерами, таблица с "заметками", находится исключительно в самом ордере. Чтобы добраться до таблицы заметок, надо открыть ордер.
Каждая заметка принадлежит конкретному ордеру, поэтому при load() нужно знать ИД ордера, чтобы получить заметки для конкретного ордера, а не все что есть. Так же при редактировании. Для таблицы "Заметки" я сделал отдельный store, потому что часто будет так что в самом ордере будут добавляться только заметки, а остальные поля не будет затронуты, соответственно нет необходимости из за одной строки, гонять на сервер все 20 полей, которые ещё будет добавлены. (На картинке только малая часть, что я пока добавил.) Мне кажется так правильней в моем случае и даже не думал что возникнут проблемы. Получается, после открытия закладки с конкретным ордером, он будет сам по себе слать данные на сервер, не затрагивая заметки, ну и заметки то же будут сами по себе. И когда произойдет добавление строки в таблицу заметок, то ордер на сервер ничего не пошлет. Как применять links я к сожалению не понял, поэтому чтобы передать данные в форму конкретного ордера, данные из строки таблицы "ордеров" сохраняются в переменную singleOrder и от туда форма заполняет свои поля. Я думал что links это что-то намертво прописанное в ViewModel, сделал вывод такой из примеров, где всегда прописаны конкретные данные. Надо пересмотреть это дело. К сожалению, данные в таблицу заметок должны грузиться при открытии ордера. Т.е. открывается закладка конкретного ордера и таблица заметок заполняется, заметками для открываемого ордера. Цитата:
|
Цитата:
Цитата:
Цитата:
{ xtype: 'noteGrid', fieldLabel: 'Заметки:', viewModel: { type: 'order' }, bind: { store: '{notes}' }, } Цитата:
Я когда задумал это дело, то рассчитывал, что при открытии формы, в которую вложена таблица заметок, то при её создании я передам в store фильтр с ИД ордера и затем произойдет autoload и всё будет как в сказке. Но в реальности autoload вызывается при открытии приложения, само собой без нужного ИД, а при открытии формы, где находится таблицы, которую надо загрузить, никакого autoload не происходит. Поэтому весь этот код в initComponent. |
Цитата:
Этот код: { xtype: 'noteGrid', fieldLabel: 'Заметки:', viewModel: { type: 'order' }, bind: { store: '{notes}' }, } нужно переписать так: { xtype: 'noteGrid', fieldLabel: 'Заметки:', viewModel: { type: 'order', stores: { notes: { type: "notes" } } }, bind: { store: '{notes}' }, } Причем до этого должен быть загружен сторе с алиасом "store.notes" (внимание!!!, нужно загружать сам КЛАСС сторе, например достаточно в приложении его прописать в stores или просто через require подгрузить класс). Цитата:
|
Цитата:
1) открытие формы нужно поменять на СОЗДАНИЕ формы и создание всего что в ней 2) автолоад нужен 3) сторе нужно подключать через алиасы, тогда автолоад будет работать не при создании приложения, а при создании формы (аля создании сторе) |
для лучшего понимания создайте код в песочнице
|
Пытаюсь, но там не меньше сложностей чем в реальном проекте. Уже не один раз пробовал, но пробиться через кучу ошибок не могу. Вот для данной проблемы пробую, но получаю ошибку, которая для меня мало информативна. Если не сложно гляньте, может поможете через проблемы песочницы пробраться, чтобы решить реальную. :)
https://fiddle.sencha.com/#fiddle/p53 Цитата:
|
вот исправленный вариант https://fiddle.sencha.com/#fiddle/p55
Файл переименовал orders -> orders.json (точнее прописал URL прямо на вкладке открытого файла, ибо просто переименование почему-то у них не работает...) Дописал прокси УРЛ: Ext.define('Fiddle.model.OrderModel', { extend: 'Fiddle.model.Base', fields: [ 'id', 'description' ], proxy: { // дописал url: "orders.json" } }); в классе Fiddle.view.Main дописал: viewModel: { type: 'order', stores: { // дописал orders: { model: "Fiddle.model.OrderModel" } } }, в классе Fiddle.view.Main расскомментировал: store: '{orders}' |
Цитата:
но код надо делать маленький, чтобы локализовать ошибку иначе очень сложно помогать... времени в обрез. |
это устаревшая опция autoCreateViewport
вместо нее mainView надо юзать |
Спасибо, буду дальше пример осиливать. Вот только как его маленьким сделать не знаю, тут по сути надо половину функционала в пример перенести, чтобы что-то походило на реальную ситуацию.
Как я понял, основная причина почему не работал пример, это отсутствие прокси с урлом в моделе. Я за основу взял https://fiddle.sencha.com/#fiddle/g56 чтобы смотреть как там сделано и повторять, но у них без прокси работает почему-то. (Ну да ладно, просто мысли в слух.) |
Читал я в документации про это, но Sencha Cmd генерирует autoCreateViewport, хотя и взята последняя версия у меня. Пробовал переделать на mainView, но там как всегда непонятные ошибки лезут, поэтому оставил как робот сделал, а то и без этого с каждой ошибкой несколько дней на место топчусь. :)
Цитата:
|
Ясно. С mainView тогда позже разберемся. Мне тоже надо его внедрять скоро в проект. Руки еще не добрались.
|
Сделал пример, массу всего пришлось нагородить, но все проблемы в файле Note.js. В этом примере то что работает в реальном коде, здесь не работает, поэтому чтобы не было ошибки, закомментировал проблемный участок.
noteStore: null, initComponent: function() { this.callParent(); this.noteStore = Ext.getStore('Fiddle.store.NoteStore'); this.on('render', this.loadStore, this); }, loadStore: function(grid) { var formId = grid.up('orderEdit').getViewModel().data.singleOrder; console.log('formId:', formId); //console.log(':', grid.up('orderEdit').getViewModel().getData()); //console.log(grid.getStore()); /*this.noteStore.load({ scope: this, params: { orderid: 'тут ид родителя таблицы, но как получить?' } });*/ }, |
|
Цитата:
У меня у формы, содержащей таблицу, есть ViewModel. К которой, я предполагаю будет обращаться и вложенная таблица. Пробовал для вложенной таблицы делать свой ViewModel, но ничего не работало. Когда убрал ViewModel таблицы и стал обращаться к ViewModel формы, то вроде заработало. [/quote] Цитата:
Получается нужно в функции initComponent самой формы, создавать вложенную таблицу и тогда автолоад заработает? Тогда по идее можно будет создать что-то вроде переменной во вложенной таблице, куда записать ИД, из создавшей её формы. Хотя попробовал в initComponent самой формы, получить её ИД, то тоже был null. В общем как всегда, непонятки и ошибки всякие. :) |
Цитата:
|
А что вообще должно получиться?
Я вижу пока грид с ордерами: items:[{ xtype: 'orderGroup', itemId: 'orderGroup_1', listeners: { vieworder: 'onCreateTab' } }] Для чего нужна эта вкладка с таблицей ордеров? Для чего нужен аккордион слева? { xtype: 'panel', layout: { type: 'accordion', animate: true }, collapsible: true, ... } В общем нужно описание ФУНКЦИОНАЛЬНОСТИ вашего примера. |
Цитата:
Ext.define('JournalApp.view.orders.OrderViewModel', { extend: 'Ext.app.ViewModel', alias: 'viewmodel.order', requires: [ 'JournalApp.model.OrderModel', //'JournalApp.model.NoteModel' 'JournalApp.store.NoteStore' ], data: { singleOrder: null }, stores: { notes: { source: 'JournalApp.store.NoteStore', } } }); Вот определение самой таблицы, где вы рекомендуете добавить ещё раздел стора: { xtype: 'noteGrid', fieldLabel: 'Заметки:', viewModel: { type: 'order', stores: { notes: { type: "notes" } } }, bind: { store: '{notes}' }, } Т.е. надо их так дублировать специально? |
Цитата:
Цитата:
|
Цитата:
В таблице ордеров щелкаем два раза на строке, чтобы её отредактировать. В результате чего откроется закладка с формой для редактирования этого ордера. Для каждого ордера создается своя закладка. Далее уже начинается проблема этой темы. Открывается закладка с формой, внутри которой будет таблица заметок,которая должна знать ИД ордера и самостоятельно обращаться с сервером. Аккордеон это хвосты, которые остались и я не смог его выпилить из примера, ошибки всякие начинают как всегда лезти, поэтому оставил как есть. Не обращайте на него внимание. Тут самое главное открытие формы редактирования ордера. |
У вас два файла: orders.json и notes.json
я так понимаю notes это подчиненная таблица, но тогда где в ней внешний ключ? например orderId |
Цитата:
|
Цитата:
В примере по сути это не важно. Нужно чтобы таблица заметок загрузилась данными из notes.json, пусть пока будет одно и то же. Ну и как-то получить ИД формы, владеющей этой таблицей. orders.json и notes.json получаются с сервера независимо и не знают друг о друге, их связывает только то что один из ИД из orders.json, после загрузке в браузер должен быть известен перед отправкой запроса о получении notes.json. Я не знаю как в песочнице урлы с параметрами формировать и отслеживать, поэтому хотя бы увидеть ИД в консоли и загрузить таблицу заметок при открытии закладки с ордером. |
Цитата:
|
1) У вас два вида: Таблица Ордеров и Просмотр Ордера
И для обоих видов вы используете одну и ту же модель вида: order А по правильному нужно на каждый вид свою модель сделать. 2) Именования нужно привести в порядок. Я уже запарился открывать файлы - каждый раз приходится думать какой файл что хранит в себе. Например для вида нужно три файла: Вид.js ВидModel.js ВидController.js где Вид это имя вида Далее, алиас должен соответствовать имени класса. Например у вас: есть xtype: 'orderGroup' ему соответствует класс Fiddle.view.OrderGrid в итоге, я смотрю на orderGroup и ищу аналогичный класс, например Fiddle.view.OrderGroup. Экономьте время на подобные поиски. Итого примерно вот что должно получиться: view - order - Order.js - OrderModel.js - OrderController.js - orders - Orders.js - OrdersModel.js - OrdersController.js - notes - Notes.js - NotesModel.js - NotesController.js Итого три вида. Причем notes это вложенный в order вид. |
Дальше, у вас один store определен. А их ведь два должно!
Сделайте два класса хранилища Notes.js Orders.js и для каждого алиасы notes n orders соответственно И после этого, в моделях видов можно прописывать {type:"алиас хранилища"} |
Можно конечно, насколько я понимаю сделать что-то вроде один ко многим и гонять заметки вместе с ордером, но у меня подобного таблице заметок будет ещё 3 штуки.
Получается ордер создается и заполняется. На этом всё. Больше он мало вероятно будет редактироваться, а вот заметки и ещё 3 подобные таблицы будут добавляться и редактироваться. Они будет состоять из 1-2 полей, а сам ордер из 20. Поэтому хочу сделать независимое обращение к сервера ордера и вложенных в него таблиц. |
Когда вы это сделаете - вы значительно упростите свой код
станет проще в нем что либо искать при анализе возможно ошибки все исчезнут сами собой - такое тоже иногда бывает |
Часовой пояс GMT +3, время: 13:07. |