2

I would like to get result from my request "instance.web.Model", then call this.super(). The matter is that "instance.web.Model" is asynchronous, so in my case the super() will be called before the request has finished.

MyObject.extend({

    init: function(parent, data){

        var newData = instance.web.Model('advanced.search')
        .call('check_duplication', [data]).done(function (name) {
            // do stuff
            return name
        });

        data = newData;
        this._super.apply(this, arguments);
        // super is called before my request is done so the new data are not sent to super.

    }
});

Do you know how to get through that? In order to pass the newData instead data as argument to the super object.

PS : I tried to encapsulate this in self : var self = this; but it does not work because it seems the parent object I extend continue to run without waiting. So I got error like "self.super(... is not a function".

MyObject.extend({

    init: function(parent, data){
        var self = this;

        var newData = instance.web.Model('advanced.search')
        .call('check_duplication', [data]).done(function (name) {
            // do stuff
            var newData = name;
            self._super.apply(self, parent, newData);
            // or self._super.apply(self, arguments); etc... I tried many variantes
        });

    }
});

To answer Bergi, as he asked I what _super() is calling. The instance.web.Model call a python script in server-side, I guess it is kind of Ajax call. But I test many case and I assume this instance.web.Model call is asynchronous. So that is the object I extend :

instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @lends instance.web.search.ExtendedSearchProposition# */{
template: 'SearchView.extended_search.proposition',
events: {
    'change .searchview_extended_prop_field': 'changed',
    'change .searchview_extended_prop_op': 'operator_changed',
    'click .searchview_extended_delete_prop': function (e) {
        e.stopPropagation();
        this.getParent().remove_proposition(this);
    }
},
/**
 * @constructs instance.web.search.ExtendedSearchProposition
 * @extends instance.web.Widget
 *
 * @param parent
 * @param fields
 */
init: function (parent, fields) {
    this._super(parent);
    this.fields = _(fields).chain()
        .map(function(val, key) { return _.extend({}, val, {'name': key}); })
        .filter(function (field) { return !field.deprecated && (field.store === void 0 || field.store || field.fnct_search); })
        .sortBy(function(field) {return field.string;})
        .value();
    this.attrs = {_: _, fields: this.fields, selected: null};
    this.value = null;
},

To go further (hope it will help you). Ok, let's see who are the superclass:

instance.web.Widget = instance.web.Controller.extend({
// Backbone-ish API
tagName: 'div',
id: null,
className: null,
attributes: {},
events: {},
/**
 * The name of the QWeb template that will be used for rendering. Must be
 * redefined in subclasses or the default render() method can not be used.
 *
 * @type string
 */
template: null,
/**
 * Constructs the widget and sets its parent if a parent is given.
 *
 * @constructs instance.web.Widget
 *
 * @param {instance.web.Widget} parent Binds the current instance to the given Widget instance.
 * When that widget is destroyed by calling destroy(), the current instance will be
 * destroyed too. Can be null.
 */
init: function(parent) {
    this._super(parent);
    // Bind on_/do_* methods to this
    // We might remove this automatic binding in the future
    for (var name in this) {
        if(typeof(this[name]) == "function") {
            if((/^on_|^do_/).test(name)) {
                this[name] = this[name].bind(this);
            }
        }
    }
    // FIXME: this should not be
    this.setElement(this._make_descriptive());
    this.session = instance.session;
},

Then, the next one:

instance.web.Controller = instance.web.Class.extend(instance.web.PropertiesMixin, {
/**
 * Constructs the object and sets its parent if a parent is given.
 *
 * @param {instance.web.Controller} parent Binds the current instance to the given Controller instance.
 * When that controller is destroyed by calling destroy(), the current instance will be
 * destroyed too. Can be null.
 */
init: function(parent) {
    instance.web.PropertiesMixin.init.call(this);
    this.setParent(parent);
},

Then :

instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
init: function() {
    instance.web.EventDispatcherMixin.init.call(this);
    this.__getterSetterInternalMap = {};
},

Then:

instance.web.EventDispatcherMixin = _.extend({}, instance.web.ParentedMixin, {
__eventDispatcherMixin: true,
init: function() {
    instance.web.ParentedMixin.init.call(this);
    this.__edispatcherEvents = new Events();
    this.__edispatcherRegisteredEvents = [];
},

Finally:

instance.web.ParentedMixin = {
__parentedMixin : true,
init: function() {
    this.__parentedDestroyed = false;
    this.__parentedChildren = [];
    this.__parentedParent = null;
},
user3350239
  • 31
  • 1
  • 5
  • Where is `._super` defined? If it is created implicitly by your framework (which one do you use?), it most likely does not work asynchronously. – Bergi Oct 08 '14 at 09:42
  • I noticed the parent call this_super() as well, perhaps it is one the issue in my case. I'm really sorry to not be more explicit in my informations, my experience in this domain is not that big, so I don't know where to get the right informations to show you – user3350239 Oct 08 '14 at 09:55
  • I wonder what `MyModel` is, and how it got that `extend` method? Are you maybe using Backbone? – Bergi Oct 08 '14 at 09:57
  • Yes there's some Backbone.js use, but I don't know really where exactly. Actually I do : instance.web.search.ExtendedSearchProposition.include({... instead of MyObject.extend({... – user3350239 Oct 08 '14 at 10:01
  • So you say that `instance.web.search.ExtendedSearchProposition` is your superclass on which you want to call the `init` via `super`? – Bergi Oct 08 '14 at 10:12
  • Yes, exactly, I override instance.web.search.ExtendedSearchProposition.init to transform original data. So I call super to pass the data I modified – user3350239 Oct 08 '14 at 10:17
  • So `MyObject` is what you shortened `instance.web.search.ExtendedSearchProposition` to? – Bergi Oct 08 '14 at 11:45
  • Yes, it is what I shortened. – user3350239 Oct 08 '14 at 12:54

1 Answers1

6

I don't think the dynamic super method that is provided by the most frameworks does work asynchronously - but if you use promises, it does need to (promises are always asynchronous).

So if you need to call the parent's initialisation method from the promise callback, you can either try

MyObject.extend({
    init: function(parent, data){
        var _super = this._super.bind(this);

        instance.web.Model('advanced.search')
        .call('check_duplication', [data])
        .done(function (name) {
            _super(parent, name);
        });
        // or in short, even just:
        // .done(this._super.bind(this, parent));
    }
});

or don't use _super at all but the native capability to reference your parent class:

MyObject.extend({
    init: function(parent, data){
        var self = this;

        instance.web.Model('advanced.search')
        .call('check_duplication', [data])
        .done(function (name) {
            instance.web.search.ExtendedSearchProposition.prototype.init // or whatever the parent method is
              .call(self, parent, newData);
        });
    }
});
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I've just tried your idea : Fisrt one A -> SyntaxError: super is a reserved identifier First one B -> TypeError: self.super is not a function Second one -> TypeError: dict.widget.attrs is undefined + infinite recursion Pass self through .done() scope is problematic – user3350239 Oct 08 '14 at 10:15
  • Oops, the first one is a dumb mistake by me; the second one needed adaption to the actual superclass (apparently `MyObject` was not the superclass) – Bergi Oct 08 '14 at 10:20
  • :) thx but there is still an issue like in case 2 -> TypeError: dict.widget.attrs is undefined. What about jQuery BlockUI plugin? I heard it is used in my program – user3350239 Oct 08 '14 at 10:47
  • I have no idea what `dict.widget.attrs` is or what it should be. – Bergi Oct 08 '14 at 10:51
  • Yes it's complicated because there are thousands lines of JS code. I thought I was by conception from my override, but seems a bit more tricky ^^ – user3350239 Oct 08 '14 at 11:01
  • Well, calling `init` asynchronously might cause some issues when the instance is used prematurely (while not initialised). If that is the reason for this problem, you might be interested in [different approaches](http://stackoverflow.com/q/24398699/1048572), if not, you should ask a new question about it. – Bergi Oct 08 '14 at 11:47