попытка получить из кнопки dijit: TypeError: this._attachEvents не определено

Я пытаюсь получить «расширенную» кнопку из dijit/Form/Button. (Я хочу передать конструктору дополнительные аргументы и инкапсулировать эти приготовления в свой производный класс. Кнопка — это просто пример, я хочу использовать ее позже с сетками и деревьями.)

К сожалению, приведенный ниже код завершается с ошибкой «TypeError: this._attachEvents is undefined» в консоли javascript firefox. Какая-то идея, что не так? Тот же код, включая минимальный HTML, готов к запуску по адресу http://jsfiddle.net/x9dLs8gz/1/<. /а>

require(["dojo/_base/declare", "dijit/form/Button", "dojo/dom", "dojo/json", "dojo/domReady!"],

function (declare, Button, dom, json) {
    declare("MyButton", Button, {
        "-chains-": {
            constructor: "manual"
        },
        constructor: function () {
            //extra calculation will go here...
            this.inherited(arguments);
        }
    });
    new MyButton({
        label: "Click Me!",
        onClick: function () {
            dom.byId("result").innerHTML += "Success";
        }
    }, "button").startup();
});

Привет, Доминик


person Dominic    schedule 18.05.2015    source источник


Ответы (2)


Если значение "-chains-" для метода constructor либо не установлено, либо установлено на "after", то метод postscript будет вызываться после того, как все унаследованные constructor будут запущены. С другой стороны, при указании "manual" postscript запускается после выполнения первого constructor (в данном случае MyButton#constructor). В результате _AttachMixins#buildRendering запускается до того, как this._attachEvents будет установлено в _AttachMixins#constructor, вызывая ошибку, которую вы видите.

Поскольку указание "manual" означает, что никакая цепочка не предполагается, конструкторы миксинов никогда не будут вызываться, даже если this.inherited правильно вызывается в цепочке. Это имеет смысл, так как базовый C3MRO выброшен в окно.

Если вам нужно продолжать использовать параметр "manual", несмотря на это, вам нужно будет 1) воссоздать все недостающие данные самостоятельно, 2) вручную вызвать конструкторы примесей (например, _AttachMixin.prototype.constructor.call(this)) или 3) преобразовать MyButton в фабрику для Button:

var createButton = (function () {
    var myButtonDefaults = { ... };

    return function (kwArgs, id) {
        var buttonId = id || 'button';
        return new Button(lang.mixin({}, myButtonDefaults, kwArgs), buttonId);
    };
})();

var myButton = createButton();
myButton.startup();
console.log(myButton instanceof Button); // true
person Matt Wistrand    schedule 18.05.2015
comment
Кроме того, вам нужно указать имя класса только тогда, когда объявленный класс будет использоваться синтаксическим анализатором Dojo. Если это не так, то лучше присвоить значение, возвращаемое declare, переменной и опустить имя при вызове declare: var MyButton = declare(Button, {});. - person Matt Wistrand; 18.05.2015
comment
Как описано на dojotoolkit.org/reference-guide. /1.10/dojo/_base/, конструкторы суперкласса всегда вызываются автоматически и всегда перед конструктором подкласса. [...] Если это не соответствует вашим потребностям, см. «Ручная цепочка конструкторов» ниже. Поскольку я хочу создать дополнительные аргументы для конструктора Button внутри конструктора MyButton, я думаю, что мне нужно руководство -chains-. Вероятно, этот пример слишком упрощен, чтобы прояснить суть. - person Dominic; 18.05.2015
comment
Я попросил помощи в немного более сложном примере здесь: mail .dojotoolkit.org/pipermail/dojo-interest/2015-May/ Возможно, этот пример лучше поясняет, как я хочу инкапсулировать аргументы конструктора в моем производном dijit. - person Dominic; 18.05.2015
comment
Спасибо за дополнительную информацию. Учитывая это, я обновил свой ответ выше, поскольку то, что вы пытаетесь сделать, невозможно, когда задействованы миксины. - person Matt Wistrand; 19.05.2015
comment
Спасибо за ваши обновления. Однако с моими ограниченными знаниями я не могу заставить его работать. И то, и другое, вызов конструктора миксина или использование вашего фабричного предложения по-прежнему приводят к одной и той же ошибке TypeError: this._attachEvents is undefined (в консоли firefox). Вы найдете готовый к запуску пример, включая конструкторы для обоих вариантов, на jsfiddle.net/x9dLs8gz/5 . Сможете ли вы запустить его без ошибок? - person Dominic; 19.05.2015
comment
Извинения; Я неправильно помнил, что возврат нового объекта из constructor ведет себя как возврат нового объекта из собственного конструктора. Итак, (еще раз) обновленный ответ демонстрирует правильный способ справиться с этим, и вы можете увидеть демонстрацию в этой обновленной версии вашей скрипки: jsfiddle.net/0o558h41/1 - person Matt Wistrand; 19.05.2015
comment
Спасибо, я до сих пор использовал этот заводской шаблон в качестве обходного пути. Однако я искал решение для создания производного класса dijit (а не только объекта), где у меня есть возможность инициализировать некоторые свойства до вызова конструктора базового класса в стиле инициализаторов C++: cprogramming.com/tutorial/initialization-lists-c++.html . Я не могу поверить, что это невозможно в javascript. Как насчет вашего второго предложения вызвать конструкторы _AttachMixin вручную - моя неудачная попытка включена в прокомментированный код на jsfiddle.net/x9dLs8gz/5? - person Dominic; 20.05.2015

Вам нужно присвоить объявленный класс переменной или объявить в другом файле и добавить его в список объектов в файле require. Также не используйте имена переменных, которые являются ключевыми словами, такими как «конструктор». ниже приведена фиксированная версия вашего примера.

require(["dojo/_base/declare", "dijit/form/Button", "dojo/dom", "dojo/json", "dojo/domReady!"],

  function(declare, Button, dom, json) {
    var MyButton = declare("MyButton", Button, {
      "-chains-": {
        constructorType: "manual"
      },
      constructor: function() {
        //extra calculation will go here...
        this.inherited(arguments);
      }
    });
    new MyButton({
      label: "Click Me!",
      onClick: function() {
        dom.byId("result1").innerHTML += "Success";
      }
    }, "button").startup();
  });
<div id="button"></div>
<div id="result1"></div>

person Thejus Kambi    schedule 18.05.2015
comment
Я не понимаю, почему вы меняете обязательный конструктор ключевых слов внутри -chains- наstructorType. Цепочка конструкторов Afaik должна быть написана так, как я. Ваш код не вызывает мой модифицированный конструктор ПЕРЕД исходным конструктором Button, как предполагалось, а ПОСЛЕ. - person Dominic; 18.05.2015
comment
Извините, я не правильно понял вопрос. Как упоминалось в ваших комментариях ранее. ручной конструктор зависит от вызова this.inherited(arguments). Ваш класс будет вызывать конструктор вызова кнопки, но конструктор классов, которые расширяет кнопка, не будет вызываться, следовательно, то, что вы пытаетесь, не может быть достигнуто. с помощью конструктора. Вместо этого попробуйте использовать метод PostCreate или PostPropertiesMixin и т. д. для достижения своих целей. - person Thejus Kambi; 18.05.2015