We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 50315
    • 7 Posts
    I would like to retrieve a value from a PHP function in a MODx Extra using Ext JS.

    Thanks to the help of Murray @ Digital Penguin, I was able to successfully set the value in the grid by adding this piece of code to the getList processor:

    public $testValue = 1234;
    public function outputArray(array $array,$count = false) {
        if ($count === false) { $count = count($array); }
        return '{"success":true,"total":"'.$count.'", "testValue":"'.$this->testValue.'", "results":'.$this->modx->toJSON($array).'}';
    }


    The issue now is that I am getting a `Uncaught TypeError: Cannot read property 'reader' of undefined` when checking the value with

    console.log('Test Value', this.store.reader.jsonData.testValue);


    Attached is a screenshot of Chore Dev Tools logging `this` inside doodles.grid.js right when the grid function starts.

    This question has been answered by muzzstick. See the first response.

      • 44195
      • 293 Posts
      Hi Alex,

      There's nothing I can see wrong with the code posted but it all depends on where you're calling console.log()

      Could it be that you're trying to access the value before the grid store has loaded?
        I'm lead developer at Digital Penguin Creative Studio in Hong Kong. https://www.digitalpenguin.hk
        Check out the MODX tutorial series on my blog at https://www.hkwebdeveloper.com
        • 50315
        • 7 Posts
        Hi Murray,

        Unfortunately I am not having success with retrieving the value. I placed a console.log() right before ending the grid function. I can successfully view properties up until

        console.log(this.store.reader);


        As soon as `.jsonData` is added, it logs as undefined. This is very unusual since it clearly loads the value and it is visible even from the very beginning of the grid function.

        Where are you placing the code to successfully load the value? Is it possible that the jsonReader might need to be extended to the Doodles class in order to access it?
          • 44195
          • 293 Posts
          Can you add this to your grid?

          ,listeners: {
              render: function() {
                  if (this.store.getCount() == 0) {
                      this.store.on('load', function() {
                          console.log(this.store.reader.jsonData.testValue);
                      }, this, {
                          single: true
                      });
                  } else {
                      console.log('store already loaded');
           
                  }
              }
          }
          
            I'm lead developer at Digital Penguin Creative Studio in Hong Kong. https://www.digitalpenguin.hk
            Check out the MODX tutorial series on my blog at https://www.hkwebdeveloper.com
            • 50315
            • 7 Posts
            That worked perfectly. One minor issue is I can't quite access the value on Ext.onReady().

            I tried creating a global object with the value but it is null before the value is set on store load.

            var global = (function () {
                return {
                    publicVal: null
                }
            })();


            What's a good way to handle this? Ultimately I'd like to check for files in the file system with PHP which would return a value and based on conditions, I'd like to display a MessageBox on page load.
              • 44195
              • 293 Posts
              Can you just add a message box to a listener so it will pop up when the grid store loads?

              Edit:

              As far as I know you won't be able to load values as fast as the page renders, it will always be slightly slower.
              You could always load the value before the grid though and only render the grid if a certain condition applies.

              For example on your home.panel.js
              You could extend it like this:

              Ext.extend(Doodles.panel.Home,MODx.Panel, {
                  checkValue: function() {
                      MODx.Ajax.request({
                          url: Doodles.config.connectorUrl
                          , params: {
                              action: 'mgr/doodle/getValue'
                          }
                          , listeners: {
                              success: {
                                  fn: function (response) {
                                      if(response.message == 1234) {
                                          this.loadGrid(); // another function you would define to load the grid
                                      }
                                  }, scope: this
                              }
                          }
                      });
                  }
              });
              


              Of course you would also need to write a processor. Let's call it getvalue.class.php

              <?php
              class GetValueProcessor extends modProcessor {
                  public $testValue;
              
                  public function process() {
                      $this->testValue = 1234;
                      return $this->success($this->testValue);
                  }
              }
              return 'GetValueProcessor';
              
              [ed. note: muzzstick last edited this post 8 years, 10 months ago.]
                I'm lead developer at Digital Penguin Creative Studio in Hong Kong. https://www.digitalpenguin.hk
                Check out the MODX tutorial series on my blog at https://www.hkwebdeveloper.com
                • 50315
                • 7 Posts
                This is definitely the direction I was thinking about going in from the start. I tried a similar Ajax call inside the grid before asking the question which always resulted in errors.

                I have followed your answer line by line several times without success. The grid would load regardless of what the value was and there was no way to log the response in the console.

                Might I ask, how did you set up your local testing environment? Based on the Developing an Extra in MODX Revolution tutorial on MODx Docs and your tutorial series part 2, I noticed that the folder structure contains a home.class.php and an index.class.php in the controller folder.

                This works for packaging but for local testing, I always get a
                Fatal error: Class 'DoodlesIndexManagerController' not found in C:\wamp\www\modx\core\model\modx\modmanagerresponse.class.php on line 185

                I noticed this same structure with other Extras. The only way I could locally work with them is to rename the controller folder. ie, _controller and to create an index.class.php in 'core>components>doodles' with modified code of both home and index combined.

                <?php
                require_once dirname(__FILE__) . '/model/doodles/doodles.class.php';
                class DoodlesIndexManagerController extends modExtraManagerController {
                    public $doodles;
                    public function initialize() {
                        $this->doodles = new Doodles($this->modx);
                
                        $this->addCss($this->doodles->config['cssUrl'].'mgr.css');
                        $this->addJavascript($this->doodles->config['jsUrl'].'mgr/doodles.js');
                        $this->addHtml('<script type="text/javascript">
                        Ext.onReady(function() {
                            Doodles.config = '.$this->modx->toJSON($this->doodles->config).';
                        });
                        </script>');
                        return parent::initialize();
                    }
                    public function getLanguageTopics() {
                        return array('doodles:default');
                    }
                    public function checkPermissions() { return true;}
                		
                	public function process(array $scriptProperties = array()) {
                
                	}
                	public function getPageTitle() { return $this->modx->lexicon('doodles'); }
                	public function loadCustomCssJs() {
                		$this->addJavascript($this->doodles->config['jsUrl'].'mgr/widgets/doodles.grid.js');
                		$this->addJavascript($this->doodles->config['jsUrl'].'mgr/widgets/home.panel.js');
                		$this->addLastJavascript($this->doodles->config['jsUrl'].'mgr/sections/index.js');
                	}
                	public function getTemplateFile() { return $this->doodles->config['templatesPath'].'home.tpl'; }
                }
                • discuss.answer
                  • 44195
                  • 293 Posts
                  In regards to the controller, things definitely changed in MODX 2.3
                  The updated docs show how to get it working. There is now only the one controller file.
                  https://rtfm.modx.com/revolution/2.x/case-studies-and-tutorials/developing-an-extra-in-modx-revolution/developing-an-extra-in-modx-revolution,-part-ii#DevelopinganExtrainMODXRevolution%2CPartII-SettinguptheControllerswithMODExt

                  The reason your grid is still loading is because is because you're still specifying it as one of the panel items. I didn't go so far as to type up the full solution before.

                  Doodles.panel.Home = function(config) {
                      config = config || {};
                      Ext.apply(config,{
                          border: false
                          ,baseCls: 'modx-formpanel'
                          ,cls: 'container'
                          ,listeners: {
                              render: function() {
                                  this.checkValue();
                              }
                          }
                          ,items: [{
                              html: '<h2>'+_('doodles.management')+'</h2>'
                              ,border: false
                              ,cls: 'modx-page-header'
                          },{
                              xtype: 'modx-tabs'
                              ,defaults: { border: false ,autoHeight: true }
                              ,border: true
                              ,items: [{
                                  id: 'main-tab'
                                  ,title: _('doodles')
                                  ,defaults: { autoHeight: true }
                                  ,items: [{
                                      html: '<p>'+_('doodles.management_desc')+'</p>'
                                      ,border: false
                                      ,style: 'margin:20px 0 0 20px;'
                                  }]
                              }]
                          }]
                      });
                      Doodles.panel.Home.superclass.constructor.call(this,config);
                  };
                  Ext.extend(Doodles.panel.Home,MODx.Panel, {
                      checkValue: function() {
                          MODx.Ajax.request({
                              url: Doodles.config.connectorUrl
                              , params: {
                                  action: 'mgr/doodle/getValue'
                              }
                              , listeners: {
                                  success: {
                                      fn: function (response) {
                                          console.log('The value returned from the processor is: '+response.message);
                                          if(response.message == 1234) {
                                              this.loadGrid();
                                          }
                                      }, scope: this
                                  }
                              }
                          });
                      },loadGrid: function() {
                          var doodlesGrid = MODx.load({
                              xtype: 'doodles-grid-doodles'
                              ,cls: 'main-wrapper'
                              ,preventRender: true
                              ,flex: 1
                          });
                          var tab = Ext.getCmp('main-tab');
                          tab.add(doodlesGrid);
                          this.doLayout();
                      }
                  });
                  Ext.reg('doodles-panel-home',Doodles.panel.Home);
                  


                  OK, things that have changed:

                  1. I gave the main tab an id of 'main-tab'
                  2. I removed the grid from the config
                  3. I added both the checkValue and loadGrid functions
                  4. I added a listener to the grid that will run the checkValue function

                  So this just shows off how to load the grid dynamically if the returned value meets a condition. If not, it doesn't load. But you could always add an else statement..

                  Hope this helps.
                    I'm lead developer at Digital Penguin Creative Studio in Hong Kong. https://www.digitalpenguin.hk
                    Check out the MODX tutorial series on my blog at https://www.hkwebdeveloper.com
                    • 50315
                    • 7 Posts
                    Thanks for all the help! I think this is very useful information for custom functionality.
                      • 44195
                      • 293 Posts
                      Glad it helped smiley

                      There's definitely not enough documentation for MODExt. Hopefully my tutorial series will help remedy that at least a little.
                        I'm lead developer at Digital Penguin Creative Studio in Hong Kong. https://www.digitalpenguin.hk
                        Check out the MODX tutorial series on my blog at https://www.hkwebdeveloper.com