Dart JavaScript output fails with: method not found: 'new ToDos:1:0' Receiver: Instance of 'JsClassMirror'

Issue

I’ve ported a handy JS library to Dart: dartscale. The crucial part of it’s functionality can be broken down to:

final Map<Symbol, ClassMirror> _registeredModules = new Map<Symbol, ClassMirror>();

register(module, [String moduleName]) {
   final uniqueModuleName = moduleName != null ? moduleName : module.runtimeType.toString();
   final Symbol uniqueModuleIdentifier = new Symbol(uniqueModuleName);

   if (_registeredModules.containsKey(uniqueModuleName)) {
     throw new StateError("Module ${moduleName} already registered!");
   }

   final ClassMirror mirror = reflect(module).type;
  _registeredModules[uniqueModuleIdentifier] = mirror;
}

start(Symbol moduleName, String id, options) {
   if (!_registeredModules.containsKey(moduleName)) {
      throw new StateError("Module ${moduleName} not registered!");
   }

   final ClassMirror mirror = _registeredModules[moduleName];
   final Symbol moduleId = id != null ? new Symbol(id) : moduleName;
   final Sandbox sandbox = new Sandbox(this.mediator);

   if (_runningModules.containsKey(moduleId)) {
      throw new StateError("Module with id #${moduleId} already running!");
   }

   final InstanceMirror moduleInstance = mirror.newInstance(new Symbol(''), [sandbox], null);
   moduleInstance.invoke(new Symbol("start"), [options]);

   _runningModules[moduleId] = moduleInstance;
}

i also provide an example

part of example;

class ToDos {

    Sandbox _sandbox;

    DivElement _contentEl;
    int _nextToDoId = 0;

    UListElement _todoList;

     ToDos ([Sandbox this._sandbox]);

     start([Map options]) {
         this._initLocalStorage();

         var html = ['<div id="module-todos">',
                       '<form>',
                          '<input type="text" class="input-medium">',
                          '<button type="submit" class="btn">Add</button>',
                       '</form>',
                       '<ul>',
                       '</ul>',
                     '</div>'].join('');

         this._contentEl = new Element.html(html);
         this._todoList = this._contentEl.query('ul');

         options['containerEl'].append(this._contentEl);

         window.localStorage.keys.forEach((key) => this._renderToDo(key));

         this._setupEvents();

         this._sandbox.channel('navigationbar').topic('filter').listen((filterContent) {
             this._filter(filterContent);
         });

        this._sandbox.channel('navigationbar').topic('clearfilter').listen((filterContent) {
           this._todoList.queryAll('li span').forEach((element) => element.parent.classes.remove('hide'));
        });
    }

    stop() {
        this._contentEl.remove();
    }

    _initLocalStorage() {
        if (window.localStorage.keys.length == 0) {
            var map = {
                "1": {
                    "subject": "Groceries: Banas and Apples",
                    "isDone": false
                },
                "2": {
                    "subject": "Taxes: take care of them",
                    "isDone": false
                },
                "3": {
                    "subject": "Bring out trash",
                    "isDone": false
                }  
            };

            for (var key in map.keys) {
                window.localStorage[key] = stringify(map[key]);
                this._nextToDoId++;
            }
        }
        else {
           for (var key in window.localStorage.keys) {
              var intKey = int.parse(key);

              if (intKey > this._nextToDoId) {
                  this._nextToDoId = intKey;
              }

              this._nextToDoId++;
           }
       }
   }

   _setupEvents() {
       var input = this._contentEl.query('input');

       input.onKeyDown.listen((event) {
          if (event.keyCode == KeyCode.ENTER) {
              event.preventDefault();

              this._addToDo(input.value);
              input.value = '';
          }
       });

       this._contentEl.query('button[type="Submit"]').onClick.listen((event) {
           event.preventDefault();

           if (input.value.length > 0) {
               this._addToDo(input.value);
               input.value = '';
           }
       });

       this._todoList.onClick.listen((MouseEvent event) {
           var el = event.target;

           if (el.classes.contains('icon-remove')) {
               this._deleteToDo(el.parent);
           }
           else if (el.classes.contains('icon-ok')) {
               this._toggleToDoDone(el.parent);
           }
       });
   }

   _renderToDo(id) {
       var todoObject = parse(window.localStorage[id.toString()]);

       var html = ['<li class="record-todo ', todoObject["isDone"]?"done":"",'" data-id="', id,'">',
                      '<span>', todoObject["subject"], '</span>',
                      '<i class="icon icon-ok"></i>',
                      '<i class="icon icon-remove"></i>',
                  '</li>'].join('');

       this._todoList.append(new Element.html(html));
   }

   _addToDo(text) {
       var todoJson = stringify({
           "subject": text,
           "isDone": false
       });

       window.localStorage[this._nextToDoId.toString()] = todoJson;
       this._renderToDo(this._nextToDoId);

       this._nextToDoId++;
   }

   _deleteToDo(todoLIElement) {
       window.localStorage.remove(todoLIElement.dataset["id"]);

       todoLIElement.remove();
   }

   _toggleToDoDone(todoLIElement) {
       var done = !todoLIElement.classes.contains('done'); 
       var id = todoLIElement.dataset["id"];
       var todoObject = parse(window.localStorage[id]);
       todoObject["isDone"] = done;
       window.localStorage[id] = stringify(todoObject);

       if (done) {
          todoLIElement.classes.add('done');
       }
       else {
          todoLIElement.classes.remove('done');
       }
   }

   _filter(content) {
       this._todoList.queryAll('li span').forEach((element) {
            if (element.innerHtml.contains(content)) {
                element.parent.classes.remove('hide');
            }
            else {
               element.parent.classes.add('hide');
            }
       });
   }
}

in my App.dart

library example;

import 'dart:html';
import 'dart:json';
import '../lib/dartscale.dart';

part 'dart/ToDos.dart';

main () {
    var core = new Core();
    core.register(new ToDos());

    core.start("ToDos", "ToDos", {
        "containerEl": query('body > .container')
    });
}

bug in dart2js ?

Solution

Solution

Turns out that dart2js has problems with mirrored calls on Methods/Constructors which have optional positional Arguments.
So changing

class ToDos {
   Sandbox _sandbox;
   ToDos([Sandbox this._sandbox]);
}

to

class ToDos {
   Sandbox _sandbox;
   ToDos(Sandbox this._sandbox); //make the argument non-optional
}

solved my Problem

Answered By – martyglaubitz

Answer Checked By – Pedro (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *