Вопрос по superboxselect

Добрый день.
Продолжаю изучать написание компонентов c использованием modExtra. В своем компоненте хочу использовать выпадающий список со множественным выбором superboxselect.
Пытаюсь разобраться c его работой на примере minishop2.
Итак, изменил схему БД modExtra.
Две таблицы, в первой таблице добавил поле 'tags':
<field key="tags" dbtype="text" phptype="json" null="true" />
для хранения выбранных значений опции 'tags'.
Вторая таблица 'testOption' список этих опций:
<object class="testOption" table="test_options" extends="xPDOObject">
		<field key="test_id" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" />
		<field key="key" dbtype="varchar" precision="255" phptype="string" null="false" />
		<field key="value" dbtype="text" phptype="string" null="true" default="" />

		<index alias="option" name="option" primary="false" unique="false" type="BTREE" >
			<column key="test_id" length="" collation="A" null="false" />
			<column key="key" length="" collation="A" null="false" />
		</index>

		<aggregate alias="Item" class="testItem" local="test_id" foreign="id" cardinality="one" owner="foreign" />
	</object>

Пока только на примере одной опции 'tags'. Её для теста через PhpMyAdmin заполнил произвольными значениями.

Далее в файле items.windows.js для методов Create и Update добавил поле:
{
	xtype: 'test-combo-options',
	name: 'tags',
	fieldLabel: _('test_multi_select'),
}
и описал xtype: 'test-combo-options':
test.combo.Options = function(config) {
    config = config || {};
    Ext.applyIf(config,{
        xtype:'superboxselect'
        ,allowBlank: true
        ,msgTarget: 'under'
        ,allowAddNewData: true
        ,addNewDataOnBlur : true
        ,resizable: true
        ,name: config.name || 'tags'
        ,anchor:'100%'
        ,minChars: 2
        ,store:new Ext.data.JsonStore({
            id: (config.name || 'tags') + '-store'
            ,root:'results'
            ,autoLoad: true
            ,autoSave: false
            ,totalProperty:'total'
            ,fields:['value']
            ,url:test.config.connector_url
            ,baseParams: {
                action: 'mgr/item/getoptions'
                ,key: config.name
            }
        })
        ,mode: 'remote'
        ,displayField: 'value'
        ,valueField: 'value'
        ,triggerAction: 'all'
        ,extraItemCls: 'x-tag'
        ,expandBtnCls: 'x-form-trigger'
        ,clearBtnCls: 'x-form-trigger'
        ,renderTo: Ext.getBody()
        ,listeners: {
            newitem: function(bs,v, f) {bs.addItem({tag: v});},
        }
    });
    config.name += '[]';
    test.combo.Options.superclass.constructor.call(this,config);
};
Ext.extend(test.combo.Options,Ext.ux.form.SuperBoxSelect);
Ext.reg('test-combo-options',test.combo.Options);

Создал файл mgr/item/getoptions.class.php
class testGetOptionsProcessor extends modObjectProcessor {
	public $classKey = 'testOption';

	/** {@inheritDoc} */
	public function process() {
		$query = trim($this->getProperty('query'));
		$limit = trim($this->getProperty('limit', 10));
		$key = $this->getProperty('key');
		$c = $this->modx->newQuery('testOption');
		$c->sortby('value','ASC');
		$c->select('value');
		$c->groupby('value');
		$c->where(array('key' => $key));
		$c->limit($limit);
        if (!empty($query)) {
			$c->where(array('value:LIKE' => "%{$query}%"));
		}
		$found = false;
		if ($c->prepare() && $c->stmt->execute()) {
			$res = $c->stmt->fetchAll(PDO::FETCH_ASSOC);
			foreach ($res as $v) {
				if ($v['value'] == $query) {
					$found = true;
				}
			}
		}
		else {$res = array();}
		if (!$found && !empty($query)) {
			$res = array_merge_recursive(array(array('value' => $query)), $res);
		}
		return $this->outputArray($res);
	}
}
return 'testGetOptionsProcessor';
В результате, при создании нового элемента в списке выбора отображаются записи из таблицы 'testOption', а также можно дописать свои. Сохраняем новый элемент, в БД у него значение поля 'tags' становиться [«test1»,«test2»], то есть все вроде бы хорошо, все сохраняется.
Проблема в том, что когда открываю добавленную запись на редактирование, поле множественного выбора не заполняется, оно пустое. Понимаю что проблема где то в процессоре get.class.php, видимо нужно Json данные подменить массивом, но как это сделать не понимаю. В minishop2 тоже не могу найти где это осуществляется. Или быть может проблема в другом? Подскажите?
P. S. Сорри, что так много писанины, просто хотелось сразу описать проблему.
Александр
03 апреля 2016, 15:54
modx.pro
4
4 087
0

Комментарии: 27

Степан Прищепенко
04 апреля 2016, 10:07
+1
нужно посмотреть идет ли запрос на сервер при открытии окна, а точнее при нажатии на список (именно в этот момент должен отправляться запрос), и соответственно смотреть что приходит (если приходит) и почему нет, если этого не происходит.
    Александр
    04 апреля 2016, 22:09
    0
    При нажатии в окне на список, если таблица testOption не пуста, то выпадает список, проблема не в этом. Проблема как раз при открытии окна на редактирование, не выводятся опции выбранные при создании.
    Например, создал новый элемент, вписал три значения опции 'tags': «test1», «test2», «test3» сохранил, смотрю в базе добавилась запись, поле 'tags' имеет значение [«test 1»,«test 2»,«test 3»], то есть данные успешно добавлены.
    По вашему совету, посмотрел какие идут запросы и ответы при нажатии кнопки Изменить.Посылается два POST запроса json типа. Первый возвращает:

    второй:

    Получается первый запрос возвращает массив 'tags', не понимаю почему тогда не отображается в поле выбора?
    Второй запрос честно говоря вообще не знаю что возвращает и почему их выполняется два.
      Александр
      04 апреля 2016, 23:49
      0
      Посмотрел запросы при изменении страницы товара в minishop2, и получился такой ответ:

      Значения возвращаемого массива, являются объектами, а у меня строки. Каким образом мне можно изменить возвращаемый ответ на массив объектов?
        Александр
        05 апреля 2016, 10:27
        0
        Сегодня немнгого разобрался как изменить вывод процессорм get.class.php
        В результате при открытии окна редактирования получаю следующий ответ:

        Но поле все равно пустое. Кто нибудь может подсказать что не так?
          Степан Прищепенко
          05 апреля 2016, 16:27
          +1
          поле пустое потому что идет второй запрос который ничего не получает и соответственно пустотой перекрывает предыдущий запрос, тут надо копать почему он вызывается. Не нужно было менять процессор, все нормально возвращалось, но тут конечно от способа хранения данных уже зависит, вощем первый вариант был правильный для JsonStore. Попробуй autoload выключи, посмотри примеры вызовов modx в папке manager или как в ms2 делается.
            Александр
            05 апреля 2016, 20:36
            0
            Все создал с начала. Процессоры не менял.
            1. Из minishop2 взял элемент списка со множественным выбором:
            test.combo.Options = function(config) {
            	config = config || {};
            	Ext.applyIf(config,{
            		xtype:'superboxselect'
            		,allowBlank: true
            		,msgTarget: 'under'
            		,allowAddNewData: true
            		,addNewDataOnBlur : true
            		,resizable: true
            		,name: config.name || 'tags'
            		,anchor:'99%'
            		,minChars: 2
            		,store:new Ext.data.JsonStore({
            			id: (config.name || 'tags') + '-store'
            			,root:'results'
            			,autoLoad: true
            			,autoSave: false
            			,totalProperty:'total'
            			,fields:['value']
            			,url: test.config.connector_url
            			,baseParams: {
            				action: 'mgr/item/getoptions'
            				,key: config.name
            			}
            		})
            		,mode: 'remote'
            		,displayField: 'value'
            		,valueField: 'value'
            		,triggerAction: 'all'
            		,extraItemCls: 'x-tag'
            		,expandBtnCls: 'x-form-trigger'
            		,clearBtnCls: 'x-form-trigger'
            		,listeners: {
            			newitem: function(bs,v, f) {bs.addItem({tag: v});}
            			/*,select: {fn:MODx.fireResourceFormChange, scope:this}
            			,beforeadditem: {fn:MODx.fireResourceFormChange, scope:this}
            			,beforeremoveitem: {fn:MODx.fireResourceFormChange, scope:this}
            			,clear: {fn:MODx.fireResourceFormChange, scope:this}*/
            		}
            		,renderTo: Ext.getBody()
            	});
            	config.name += '[]';
            	test.combo.Options.superclass.constructor.call(this,config);
            };
            Ext.extend(test.combo.Options,Ext.ux.form.SuperBoxSelect);
            Ext.reg('test-combo-options',test.combo.Options);
            События select, beforeadditem, beforeremoveitem, clear закккоментировал, иначе выдает ошибку, они вроде бы не принимают участи при выводе.

            2. На форму окна пометил элементы списка:
            {
            	xtype: 'test-combo-options',
            	description: _('test_tags_help'),
            	name: 'tags'
            },
            3. Из из minishop2 добавил процессор получения выпадающего списка getoptions.class.php:
            class testGetOptionsProcessor extends modObjectProcessor {
            	public $classKey = 'testOption';
            
            	/** {@inheritDoc} */
            	public function process() {
            		$query = trim($this->getProperty('query'));
            		$limit = trim($this->getProperty('limit', 10));
            		$key = $this->getProperty('key');
            
            		$c = $this->modx->newQuery('testOption');
            		$c->sortby('value','ASC');
            		$c->select('value');
            		$c->groupby('value');
            		$c->where(array('key' => $key));
            		$c->limit($limit);
                    if (!empty($query)) {
            			$c->where(array('value:LIKE' => "%{$query}%"));
            		}
            		$found = false;
            		if ($c->prepare() && $c->stmt->execute()) {
            			$res = $c->stmt->fetchAll(PDO::FETCH_ASSOC);
            			foreach ($res as $v) {
            				if ($v['value'] == $query) {
            					$found = true;
            				}
            			}
            		}
            		else {$res = array();}
            
            		if (!$found && !empty($query)) {
            			$res = array_merge_recursive(array(array('value' => $query)), $res);
            		}
            		return $this->outputArray($res);
            	}
            }
            
            return 'testGetOptionsProcessor';
            4. Выпадающий список выводиться из таблицы 'testOption', для теста заполнил её вручную.

            5. После создания элементы попадают в таблицу 'testItem':

            Поле 'tags' успешно заполнено. В таблицу 'testOption' пока не добавляю.

            6. Открываю окно для редактирования, выпадающий список из 'testOption' выводиться, а сохраненные данные [«test1»,«test2»] из 'testItem' нет:


            Очередность запросов тут мне кажется не при чем, тот запрос который в предыдущем примере пустой выводился, это вывод выпадающего списка:

            видимо в предыдущем примере у меня таблица 'testOption' просто была пустая.
            Более того в minishop2 на запрос касаемо вывода опций tags, ответ только такого типа и выводиться.
            Где передаются уже выбранные опции я не нашел.
              Володя
              05 апреля 2016, 20:51
              +1
              в minishop2 есть вот такое — github.com/bezumkin/miniShop2/blob/master/core/components/minishop2/controllers/product/update.class.php#L196-L213
              можно сделать получение в get процессоре например так — github.com/vgrish/modForms/blob/master/core/components/modforms/processors/mgr/form/get.class.php#L30-L46
                Александр
                06 апреля 2016, 19:24
                0
                В minishop2 нашел таки где идет запрос на вывод списока выбранных значений superboxselect, оказывается список формируется процессором «mgr/product/getlist» при открытии категории товара и выводиться в виде json строки:

                Пробовал добавлять в свой getlist.class.php в метод prepareRow(xPDOObject $object) следующий код:
                public function prepareRow(xPDOObject $object) {
                	$array = $object->toArray();
                	...
                	$data = $array['tags'];
                	$array['tags']=$this->modx->toJSON($data);
                	return $array;
                }
                Вместо массива стала выводится json строка, но толку это не дало, при открытии окна редактирования поле superboxselect все равно пустое.
                Уже наверное все варианты перепробовал…
                  Володя
                  06 апреля 2016, 21:51
                  +1
                  если быть повнимательнее то можно заметить что формат немного не тот…
                  и мало того у вас вообще в tags строка
                    Александр
                    06 апреля 2016, 22:03
                    0
                    Это не у меня, это скрин с minishop2, а там эта строка прекрасно работает
                      Володя
                      06 апреля 2016, 22:16
                      +1
                      кинь в личку где посмотреть/зайти — быстрее будет…
                  Степан Прищепенко
                  06 апреля 2016, 22:00
                  +1
                  у тебя уже ответ в виде json приходит, вот на этой картинке ответ от сервера правильный для твоего случая. Давай еще раз я правильно понимаю что проблема заключается в следующем:

                  1. У тебя есть некая таблица ExtJs с кнопкой добавления записей
                  2. Ты нажимаешь на кнопку и в некоем поле открывшегося окна ты добавляешь запись, эта запись добавляется в таблицу БД.
                  3. Затем в таблице из пункта 1 ты нажимаешь на некую запись-строку (уже другой таблицы, и не известно как туда попала эта запись, но это не важно) и у тебя открывается окно редактирования записи.
                  4. При открытии это окно автоматически заполняется данными и скорее всего поле tag тоже заполняется.
                  5. Ты нажимаешь на выпадающий список Tag у тебя идет запрос на сервер, в котором он получает ответ, для примера содержащий 1,2,3,4 а в выпадающем списке у тебя отображается только 1,2
                  6. И чтобы ты не делал ты всегда видишь 1,2. Имею ввиду обновлял грид, перезагруж страницу, добавлял новые данные напрямую итд.

                  Я правильно понял проблему?
                    Александр
                    06 апреля 2016, 22:18
                    0
                    1. Да, просто тестовый modExtra. В схему для основной таблицы testItem добавил поле для хранения выбранных пунктов списка выбора, обзовем его tags. И добавил таблицу testOption для хранения самих выпадающих пунктов, эту таблицу вообще пока можно убрать из рассмотрения, она только выпадающий список формирует на данном этапе.
                    2. Да.
                    3. Не совсем, открываю на редактирование запись из первой таблицы, открывается окно редактирования.
                    4. Да, все поля заполнены кроме поля tags из 1 пункта.
                    5. Нет, выпадающий список формируется полностью на основе таблицы testOption из пункта 1. С этим проблем нет.
                    6. Чтобы я не делал я не вижу сохраненные значения tags из таблицы testItem.
                      Александр
                      06 апреля 2016, 22:40
                      0
                      И вам тоже скинул доступ в админку
                  Степан Прищепенко
                  06 апреля 2016, 16:31
                  +1
                  когда открываешь окно редактирования, а потом тычешь на список запрос отправляется на сервер? ответ приходит с новыми данными? Что произойдет если в гриде снизу нажать кнопку обновления таблицы и снова открыть редактирование? Проблема в чем, в том что ты не видишь новыйх данных вообще, или в том что сразу после сохранения их не видно в форме редактирования? Если второй вариант, то возможно у тебя 2 проблемы а не одна, выражается в следующем: когда ты открываешь окно редактирования, и если у него тот же id что и окна создания записи, то возможно, что оно не было уничтожено при предыдущем закрытии (обрати внимание на это). Далее, у всех элементов вызывается метод setValue (который сам вызывает запрос на обновление данных, метод doQuery) в кот передается значение. Т.к. выпад список работает по приципу ключ-значение, то скорее всего при открытии формы в него передается значение из таблицы, а не ключ, как результат список будет всегда пуст, при условии что ключ не == значению. Я не знаю что внутри superboxselect который ты используешь, ибо их несколько версий, я к примеру переделал его, т.к. работает признаться он криво, но на сколько я помню, в стандартной версии если у него есть данные в store, то второй раз они уже не вызываются (возвращаемся к тому что у тебя используется одно и тоже окно). Ну и проверить надо что valueField и displayField правильно указаны (но дело не в этом я думаю).
                    Александр
                    06 апреля 2016, 19:02
                    0
                    1.
                    когда открываешь окно редактирования, а потом тычешь на список запрос отправляется на сервер?
                    Да отправляется, ответ приходит с данными выпадающего списка, список открывается
                    2.
                    Что произойдет если в гриде снизу нажать кнопку обновления таблицы и снова открыть редактирование?
                    Ничего, просто открывается окно как в первый раз
                    3.
                    Проблема в чем
                    В том что если я открываю окно редактирования, я не вижу в нем сохраненые значения superboxselect.
                    4.
                    и если у него тот же id
                    Id окон разные, я в чистой modExtra экспериментирую, соответственно 'test-item-window-create' и 'test-item-window-update'
                    5.
                    Я не знаю что внутри superboxselect
                    superboxselect встроенный в MODX версии 2.3.5-pl. По крайней мере в minishop2 установленном на этом же хосте, этот механизм работает.
                    6.
                    valueField и displayField правильно указаны
                    По полям, можно выше взглянуть, я куски кода приводил которые брал из minishop2. Эти поля не трогал.
          Александр
          06 апреля 2016, 23:29
          +1
          Проблема решена! Спасибо огромное Владимиру за помощь!!!
            Володя
            07 апреля 2016, 18:10
            +1
            пожалуйста
            Denis
            27 июля 2016, 11:23
            0
            Здравствуйте, выложите пожалуйста решение проблемы, уже больше недели не могу вывести сохраненные значения в superboxselect.
            У меня:
            1) Поле выводитсся так же в окне редактирования.
            2) Процессор, при открытии окна редактирования возвращает json вида:
            {«success»:true,«message»:"",«total»:0,«data»:[],«object»:{«id»:155,«code»:«iii»,«type»:1,«products»:«1,2,3,4,5,6,7,8»}}
            Где «products» поле которое нужно отрендерить в superboxselect.
            Остальное все так же как и в описаной Вами проблеме.
              Aborrol
              09 июня 2022, 03:23
              0
              Прошу прощения за некропостинг, но вдруг кому-то поможет решение.
              В get процессор
              public function cleanup()    {
                      $data = $this->object->toArray();
                      if($data['categories']){
                          $data['categories[]'] = [];
                          foreach($data['categories'] as $id){
                              $data['categories[]'][]['id'] = $id;
                          }
                      }
                      return $this->success('', $data);
                  }
              Чтобы вернулось из процессора поле с [] и массивом для поля valueField в компоненте superboxselect
              [categories] => Array
                      (
                          [0] => 1
                          [1] => 3
                      )
              
                  [categories[]] => Array
                      (
                          [0] => Array
                              (
                                  [id] => 1
                              )
              
                          [1] => Array
                              (
                                  [id] => 3
                              )
              
                      )
              Boris Akimenko
              19 марта 2017, 10:00
              +2
              Народ, вы конечно извините, но написать в чем причина была вам что-то не позволяет?
              Это сообщество единоличников, или всё же разработчиков? Как у человека проблема — он пишет каждые пять минут, а как решение найдено — идите все нахер? :)
              Опишите решение, коллеги.
                Boris Akimenko
                02 апреля 2017, 12:30
                0
                Решение есть тут
                Параметр
                value:'{$values}',
                , или как в моем случае
                dataIndex : 'specialties'
                , где 'specialties' это массив переданный из процессора.
                  SEQUEL.ONE
                  14 июня 2020, 00:42
                  0
                  Точно такая же проблема. Не могу вывести значения при редактировании и ещё в Grid таблицу modx.pro/help/20443

                  Вы не поможете? Не могу понять что не так?! =(
              Кровельный
              16 июня 2023, 12:21
              0
              Как добавить множественный список с автодополнением в ресурс/документ (свое кастомное поле tags_cloud), также как реализовано tags в ms2?
              Например, у ресурса уже есть в бд значения ["тег 1","тег 2","тег 3"], но в супер-селекте они не выводятся и не вводятся. Есть у кого подсказка или решение?

              В таблице modx_site_content добавлена структура tags_cloud
              Плагин:
              <?php
              switch ($modx->event->name) {
                  case "OnMODXInit":
                      $modx->loadClass('modResource');    
                      $map = array(
                          'modResource' => array(
                              'fields' => array(
                                  'tags_cloud' => null,
                              ),
                              'fieldMeta' => array(
                                  'tags_cloud' => array(
                                      'dbtype' => 'varchar',
                                      'precision' => '100',
                                      'phptype' => 'json',
                                      'null' => true,
                                  ),
                              ),
                          ),
                      );
                      
                      foreach ($map as $class => $data) {
                          $modx->loadClass($class);
                          foreach ($data as $tmp => $fields) {
                              if ($tmp == 'fields') {
                                  foreach ($fields as $field => $value) {
                                      foreach (array('fields', 'fieldMeta', 'indexes') as $key) {
                                          if (isset($data[$key][$field])) {
                                              $modx->map[$class][$key][$field] = $data[$key][$field];
                                          }
                                      }
                                  }
                              } elseif ($tmp == 'composites' || $tmp == 'aggregates') {
                                  foreach ($fields as $alias => $relation) {
                                      if (!isset($modx->map[$class][$tmp][$alias])) {
                                          $modx->map[$class][$tmp][$alias] = $relation;
                                      }
                                  }
                              }
                          }
                      }
                      break;
                  case 'OnDocFormPrerender':
                      $tags_cloud = $resource->get('tags_cloud');
                      $tags_cloud = $modx->toJSON($tags_cloud);
                      $modx->log(1, print_r($tags_cloud, 1));
                      
                      $modx->controller->addHtml("
                      <script type='text/javascript'>
                          Ext.ComponentMgr.onAvailable('modx-panel-resource', function(){
                              const leftCol = this.items[1].items[0].items[0].items[0];
                              const rightCol = this.items[1].items[0].items[0].items[1];
                              config = [] || config || {};
                              
                              const tags_cloud = {
                                  typeAhead: true,
                                  triggerAction: 'all',
                                  lazyRender: true,
                                  resizable: true,
                                  anchor: '100%',
                                  description: '<b>[[*tags_cloud]]</br>Облако тегов</b>',
                                  fieldLabel: 'Облако тегов',
                                  id: 'modx-resource-tags_cloud',
                                  maxLength:255,
                                  msgTarget: 'under',
                                  name:'tags_cloud',
                                  hiddenName: 'tags_cloud',
                                  xtype: 'superboxselect', // combo, modx-combo - одиночный выбор, а combobox и другие не работают
                                  store: new Ext.data.JsonStore({
                                      id: 'tags_cloud-store',
                                      root: 'results',
                                      autoLoad: false,
                                      autoSave: false,
                                      totalProperty: 'total',
                                      //fields: ['value'],
                                      fields: $tags_cloud,
                                      url: MODx.config.connectorUrl,
                                      baseParams: {
                                          action: 'mgr/item/getoptions',
                                          key: 'tags_cloud'
                                      }
                                  }),
                                  mode: 'remote',
                                  displayField: 'value',
                                  valueField: 'value',
                                  
                                  extraItemCls: 'x-tags_cloud',
                                  expandBtnCls: 'x-form-trigger',
                                  clearBtnCls: 'x-form-trigger',
                                  renderTo: Ext.getBody(),
              
                                  editable: true,
                                  selectOnFocus: false,
                                  preventRender: true,
                                  forceSelection: true,
                                  enableKeyEvents: true,
                                  displayField: ['value'],
                                  valueField: ['value'],
                                  //value: $tags_cloud,
                                  hiddenValue: $tags_cloud,
                                  emptyText: 'Выбирете или введите теги',
                                  tpl: new Ext.XTemplate('<tpl for=\".\"><div class=\"x-combo-list-item\"><span>{value}</span></div></tpl>',{ compiled: true })
                              }
              
                              rightCol.items.splice(3, 0,  tags_cloud); // поле выводится там где сменить Шаблон, Пункт меню
                          });
                      </script>");
                  break;
              }
                Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                27