Answers.Body: <p>So the reason your code worked with Craft 3 was that it wasn't typed, so it was okay with an empty table being stored as a string.</p>
  <p>As for why your normalization via event doesn't work:</p>
  <ul>
  <li>Does the event get triggered?</li>
  <li>If yes, maybe try:</li>
  </ul>
  <pre class="lang-php prettyprint-override"><code>    if (empty($settings['whitelist'])) {
        $settings['whitelist'] = [];
      }
  </code></pre>
  <p>...in case the value is coming in as <code>null</code> or some other empty value?</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-08-14T20:23:58.300Z
Answers.Text: Thanks @andrew, the 'EVENT_BEFORE_SAVE_SETTINGS' event isn't being triggered at all in Craft 3. I've tried using the "EVENT_BEFORE_SAVE_PLUGIN_SETTINGS" instead, which does trigger, however when the whitelist field is empty the type error gets thrown before the event does.
Answers.UserDisplayName: Mark Notton
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-08-13T22:10:37.190Z
Answers.LastActivityDate: 2022-08-13T22:10:37.190Z
Answers.UserDisplayName: andrew.welch
Answers.Body: <p><strong>Prevent users on Craft 3 from being able to submit an empty table:</strong></p>
  <p>In the plugins settings.twig file update the the 'whitelist' rows variables to  an empty array if it's empty and the Craft version is starts with &quot;3&quot;</p>
  <pre><code>{% if whitelist is empty and craft.app.getVersion()|first == '3' %}
    {% set whitelist = whitelist is empty ? { item : '' } %}
  {% endif %}
  </code></pre>
  <p>If you are using the 'allowReorder' property; it is worth hiding the first delete button on the first row item:</p>
  <pre class="lang-css prettyprint-override"><code>{% css %}
    #settings-whitelsit tbody &gt; tr:first-of-type a.delete { display:none; }
  {% endcss %}
  </code></pre>
  <p>There is a minRows property that can be defined in the editableTable options:</p>
  <pre><code>forms.editableTable({
    minRows : craft.app.getVersion()|first == '3' ? 1 : null,
    ...
  })
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-08-20T23:04:59.960Z
Answers.LastActivityDate: 2022-08-22T07:32:28.400Z
Answers.LastEditDate: 2022-08-22T07:32:28.400Z
Answers.UserDisplayName: Mark Notton
Body: <p>My plugin uses a <code>{{ forms.editableTable({...}) }}</code> field within the settings.twig. When the field has row items it will save just fine, but when the table is empty it attempts to save it as an empty string. This throws an error:</p>
  <p><code>Typed property marknotton\myplugin\models\Settings::$whitelist must be array, string used</code></p>
  <p>I would have expected it to save an empty array. Especially as I've defined the default value as an array in the Settings class.</p>
  <p>Following <a href="https://github.com/craftcms/cms/issues/3105#issuecomment-405650687" rel="nofollow noreferrer">Brandons suggestion from an older issue</a>, I have tried to amend the setting before it is saved via an Event listener:</p>
  <pre class="lang-php prettyprint-override"><code>// This is in my plugins init() method
  Event::on(
    MyPlugin::class,
    MyPlugin::EVENT_BEFORE_SAVE_SETTINGS,
    [Settings::class, 'onBeforeSaveSettings']
  );
  </code></pre>
  <pre class="lang-php prettyprint-override"><code>class Settings extends Model {
  
    public array $whitelist = [];
  
    public function rules(): array 
    {
      return [
        ['whitelist', ArrayValidator::class],
      ];
    }
  
    public static function onBeforeSaveSettings(ModelEvent $event): ModelEvent
    {
      $plugin = $event-&gt;sender;
      $settings = $plugin-&gt;getSettings();
  
      if ( is_string($settings['whitelist']) ) {
        $settings['whitelist'] = [];
      }
      
      return $event;
    }
  
  }
  </code></pre>
  <p>This works perfectly in Craft 4, but in Craft 3 my 'onBeforeSaveSettings' method isn't getting called at all.</p>
  <p>Is this just a novice data type issue I'm overlooking? Or is the <code>EVENT_BEFORE_SAVE_SETTINGS</code> event failing to run on Craft 3 specifically?</p>
  
Tags: <craft3><plugin-development><settings>
Title: Plugin 'editableTable' settings field returns incorrect type when empty
ThreadText: # Plugin 'editableTable' settings field returns incorrect type when empty
  
  (Asked by: username_0 on 2022-08-11)
  
  My plugin uses a `{{ forms.editableTable({...}) }}` field within the settings.twig. When the field has row items it will save just fine, but when the table is empty it attempts to save it as an empty string. This throws an error:
  
  `Typed property username_0\myplugin\models\Settings::$whitelist must be array, string used`
  
  I would have expected it to save an empty array. Especially as I've defined the default value as an array in the Settings class.
  
  Following [Brandons suggestion from an older issue](https://github.com/craftcms/cms/issues/3105#issuecomment-405650687), I have tried to amend the setting before it is saved via an Event listener:
  
  ```php
  // This is in my plugins init() method
  Event::on(
    MyPlugin::class,
    MyPlugin::EVENT_BEFORE_SAVE_SETTINGS,
    [Settings::class, 'onBeforeSaveSettings']
  );
  
  ```
  
  ```php
  class Settings extends Model {
  
    public array $whitelist = [];
  
    public function rules(): array 
    {
      return [
        ['whitelist', ArrayValidator::class],
      ];
    }
  
    public static function onBeforeSaveSettings(ModelEvent $event): ModelEvent
    {
      $plugin = $event->sender;
      $settings = $plugin->getSettings();
  
      if ( is_string($settings['whitelist']) ) {
        $settings['whitelist'] = [];
      }
      
      return $event;
    }
  
  }
  
  ```
  
  This works perfectly in Craft 4, but in Craft 3 my 'onBeforeSaveSettings' method isn't getting called at all.
  
  Is this just a novice data type issue I'm overlooking? Or is the `EVENT_BEFORE_SAVE_SETTINGS` event failing to run on Craft 3 specifically?
  
  **Tags:** craft3, plugin-development, settings
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2022-08-13. Score: 1
  
  So the reason your code worked with Craft 3 was that it wasn't typed, so it was okay with an empty table being stored as a string.
  
  As for why your normalization via event doesn't work:
  
  * Does the event get triggered?
  * If yes, maybe try:
  
  ```php
      if (empty($settings['whitelist'])) {
        $settings['whitelist'] = [];
      }
  
  ```
  
  ...in case the value is coming in as `null` or some other empty value?
  
  > **Comments:**
  > **username_0**: Thanks @andrew, the 'EVENT_BEFORE_SAVE_SETTINGS' event isn't being triggered at all in Craft 3. I've tried using the "EVENT_BEFORE_SAVE_PLUGIN_SETTINGS" instead, which does trigger, however when the whitelist field is empty the type error gets thrown before the event does.  
  
  ---
  
  ### Answer by username_0 on 2022-08-20. Score: 1
  
  **Prevent users on Craft 3 from being able to submit an empty table:**
  
  In the plugins settings.twig file update the the 'whitelist' rows variables to an empty array if it's empty and the Craft version is starts with "3"
  
  ```
  {% if whitelist is empty and craft.app.getVersion()|first == '3' %}
    {% set whitelist = whitelist is empty ? { item : '' } %}
  {% endif %}
  
  ```
  
  If you are using the 'allowReorder' property; it is worth hiding the first delete button on the first row item:
  
  ```css
  {% css %}
    #settings-whitelsit tbody > tr:first-of-type a.delete { display:none; }
  {% endcss %}
  
  ```
  
  There is a minRows property that can be defined in the editableTable options:
  
  ```
  forms.editableTable({
    minRows : craft.app.getVersion()|first == '3' ? 1 : null,
    ...
  })
  
  ```
  
  
  ---
  
  