Error | Removing disallowed attribute on SelectEle

2019-08-11 15:55发布

问题:

I am trying to use a button to add a new row in an html table when the button is clicked, and another button to remove the row/s with its checkbox checked. I am experience two problems:

  1. Whenever the add-button is clicked I get Removing disallowed attribute SELECT on-change="{{ onChangeTypeFired }}"
  2. If I select two checkboxes and clicked the delete row button it throws an indexIndexSizeError: Index or size was negative, or greater than the allowed value. The index provided (2) is greater than the number of rows in the table (2).

The files are shown below

.html

        <!DOCTYPE html>

        <link rel='import' href='../../../../packages/polymer/polymer.html' >

        <link rel='import' href='../../../../packages/paper_elements/paper_checkbox.html' >
        <link rel='import' href='../../../../packages/paper_elements/paper_button.html' >
        <link rel='import' href='../../../../packages/core_elements/core_collapse.html' >
        <link rel='import' href='../../../../packages/core_elements/communication_icons.html' >

        <polymer-element name='phone-form'>
          <template>

            <div
              class='parent-container'>
              <paper-button id='add-btn' on-click='{{toggle}}'>
                <core-icon id='toggle-btn-icon' icon=''></core-icon>
                Phone
                <core-icon id='validation-icon' class='margin-l5px' icon=''></core-icon>
              </paper-button>



            <table id='table' border='1' width='350px'>
                <tbody><tr>
                    <td><input name='chk' type='checkbox'></td>
                    <td>
                      <select id='phoneType' class='width95percent'
                          selectedIndex='{{typeSelected}}' 
                          on-change='{{onChangeTypeFired}}'>
                          <option template repeat='{{key in types.keys}}' 
                          value='{{types[key]}}'>{{types[key]}}
                        </option>

                      </select>
                    </td>
                </tr>
            </tbody></table>
             </div>
             <div>
              <paper-button raised id='add-row-btn' class='margin-8px'

                on-click='{{addRow}}'>
                Add Row
                <core-icon id='add-row-btn-icon' icon='check-all'></core-icon>
              </paper-button>

              <paper-button raised id='delete-row-btn' class='margin-8px'

                on-click='{{deleteRow}}'>
                Delete Selected Row(s)
                <core-icon id='delete-row-btn-icon' icon='check'></core-icon>
              </paper-button>

             </div>



            </div>
          </template>
          <script type='application/dart' src='phone_form.dart'></script>
        </polymer-element>

.dart

import 'package:polymer/polymer.dart';
import 'dart:html' as dom;

import 'package:paper_elements/paper_button.dart' show PaperButton;
import 'package:core_elements/core_collapse.dart';

//import 'package:epimss_shared/epimss_shared.dart';
//import 'package:epimss_shared/epimss_shared_client.dart' hide DataEvent;

@CustomTag('phone-form')
class PhoneForm extends PolymerElement {

  @observable String errorMsg;
  String topic;
  PaperButton addBtn;

  int typeSelected = 0;
  CoreCollapse coreCollapse;

  @observable
  Map<String, String> types = <String, String> {
    '': '',
    'Car': 'Car',
    'Direct': 'Direct',
    'Fax': 'Fax',
    'Home': 'Home',
    'Mobile': 'Mobile',
    'Video': 'Video',
    'Work': 'Work'
  };

  PhoneForm.created() : super.created();


void toggleCoreCollapse() {
  coreCollapse.toggle();
}

  void onSelectTypeFired()
  {

  }

  void onChangeTypeFired( dom.Event e, var detail, dom.SelectElement target)
  {
    print(target.value);
  }

  void addRow()
  {
    var table = $['table'];
    var rowCount = table.rows.length;
    var row = table.insertRow(rowCount);
    var colCount = table.rows[0].cells.length;

    for(var i = 0; i<colCount; i++ )
    {
      var newcell = row.insertCell(i);
      newcell.innerHtml = table.rows[0].cells[i].innerHtml;

      switch(newcell.childNodes[0].runtimeType.toString())
      {
        case 'text':
          newcell.childNodes[0].value = '';
          break;

        case 'checkbox':
          newcell.childNodes[0].checked = false;
          break;

        case 'select':
          newcell.childNodes[0].selectedIndex = 0;
          break;
      }
    }
  }


  void deleteRow()
  {

    var rowsToDelete = [];

    try{
      var table = $['table'];
      var rowCount = table.rows.length;

      for(var i = 0; i < rowCount; i++)
      {
        var row = table.rows[i];
        var chkbox = row.cells[0].childNodes[0];

        if(chkbox != null && chkbox.checked)
        {
          if(rowCount <= 1)
          {
            print('Cannot delete all the rows.');
            break;
          }
          else
          {
            rowsToDelete.add(i);
          }
        }
      }

      rowsToDelete.forEach( (row)
          {
            table.deleteRow(row);
          });
    }
    catch(e)
    {  print(e); }
  }


  @override
  void attached() {
    super.attached();
    topic = this.dataset['topic'];

    coreCollapse = $['core-collapse'];

    addBtn = $['add-btn'];
  }



}

Thanks for your help.

回答1:

It is probably caused by this line

newcell.innerHtml = table.rows[0].cells[i].innerHtml;

You need to specify which elements and tags are allowed to be added to the DOM from a string. see https://stackoverflow.com/a/27334820/217408 for more details.

That doesn't apply when you generate the elements imperatively like new DivElement().

In your example it would probably easier and better to do something like

newcell.children.clear();
newcell.children.addAll(table.rows[0].cells[i].children.map((c) => 
    c.clone(true)));

Caution: I'm not sure about how the code should exactly look like but I think you get the idea. If you can't work it out add a comment and I'll have a closer look.