peerlibrary / meteor-blaze-components

Reusable components for Blaze
http://components.meteorapp.com/
BSD 3-Clause "New" or "Revised" License
354 stars 26 forks source link

How to display base class data #70

Closed bartonhammond closed 9 years ago

bartonhammond commented 9 years ago

I apologize if this is obvious to everyone else...

If my base component displays data, shouldn't my component that inherits from it display the same provided I do nothing to prevent it?

For example, my base template atNavButton is like this:

<template name="atNavButton">
  <div>{{text}}</div> //text is hard coded to return string 'AT.prototype'
</template>

And my new component WebixNavButton looks like this:

var WebixNavButton = BlazeComponent.extendComponent({
  template: function () {
    return 'atNavButton';
  },
  text: function() {
    debugger;
  },
  events: function () {
    return [{
      'click *': this.onClick
    }];
  },
  onClick: function (event) {
    console.log('WebixNavButton.onclick');
  }
}).register('WebixNavButton');

My index.html page is

<body>
  atNavButton:  {{> atNavButton}}
  <br>
  WebixNavButton: {{> WebixNavButton}}
</body>

When running http://webix-components.meteor.com/, I expected to see the WebixNavButton display the same 'text' as the base class, namely AT.prototype.

Is it possible to get access to the value from the base class helper function "text"?

mitar commented 9 years ago

atNavButton is in your case not a base class, nor a Blaze Component, but just a template. You cannot inherit from template. Templates in Blaze Components are used only for HTML content, events and helpers do not propagate to the component. So inheritance between Blaze Components (if you would be doing it) comes from JavaScript inheritance between classes, not because you are using a template.

The main reason why this is not so is because in Blaze template helpers this is a data context, while in Blaze Components methods this is a Blaze Component. So by blindly inheriting template helpers most of them would not work properly anyway.

You could create a function for yourself which takes a template as input, and copies its template helpers to the prototype of your Blaze Component, passing to each of them data context as this.

bartonhammond commented 9 years ago

I'm confused more now. I am following exactly (imo) the very first example presented at http://components.meteor.com/. Rather then the "input" template/js I am using "atNavButton" template/js. What is different?

mitar commented 9 years ago

Can you show me where is code for 'text' as the base class, namely AT.prototype..

mitar commented 9 years ago

BTW, you could do something like:

var WebixNavButton = BlazeComponent.extendComponent({
  template: function () {
    return 'atNavButton';
  },
  text: function() {
    return Blaze._getTemplateHelper(Template.atNavButton, 'text', Template.instance)();
  },
  events: function () {
    return [{
      'click *': this.onClick
    }];
  },
  onClick: function (event) {
    console.log('WebixNavButton.onclick');
  }
}).register('WebixNavButton');
bartonhammond commented 9 years ago

So the atNavButton.js is

// Simply 'inherites' helpers from AccountsTemplates
Template.atNavButton.helpers(AccountsTemplates.atNavButtonHelpers);
// Simply 'inherites' events from AccountsTemplates
Template.atNavButton.events(AccountsTemplates.atNavButtonEvents);

And AccountsTemplates.js is


// Constructor
AT = function() {
};

AT.prototype.atNavButtonHelpers = {
  text: function(){
    return 'AT.prototype';
    }
};

AT.prototype.atNavButtonEvents = {
    'click #at-nav-button': function(event){
      event.preventDefault();
      console.log('AT.prototype.atNavButtonEvents.click');
    },
};
AccountsTemplates = new AT();

Side note - I'm trying to incorporate the ui library http://webix.com with the "useraccounts" package. This code mirrors what I'll encounter when I actually add the "useraccounts:core" package.

As you can see from http://webix-components.meteor.com/ that the atNavButton renders just fine.

Thanks for your help!

mitar commented 9 years ago

Yes. As I said, template helpers are not copied over to the Blaze Component. You created a template atNavButton and assigned some template helpers to it (including text). You are then using that template as a Blaze Component template. Blaze Components use template only as content, ignoring events and template helpers. I explained above why (because this is not scoped correctly).

bartonhammond commented 9 years ago

Ok...this worked (note the function invocation ...)

  text: function() {
    return Blaze._getTemplateHelper(Template.atNavButton, 'text', Template.instance)();//note ()
  },

Is there anyway to have this execute automatically such that if I didn't like that default behavior I'd have to implement my own version of this "text" method? Seems it should work by default since this is class based inheritance .

bartonhammond commented 9 years ago

I'm confused (even more). So in your initial example both the template and the embedded html element is called "input". I assumed you were subclassing the template named 'input' which is the pattern I followed.

On Wed, Sep 16, 2015 at 7:01 PM, Mitar notifications@github.com wrote:

Yes. As I said, template helpers are not copied over to the Blaze Component. You created a template atNavButton and assigned some template helpers to it (including text). You are then using that template as a Blaze Component template. Blaze Components use template only as content, ignoring events and template helpers. I explained above why (because this is not scoped correctly).

— Reply to this email directly or view it on GitHub https://github.com/peerlibrary/meteor-blaze-components/issues/70#issuecomment-140929200 .

mitar commented 9 years ago

No, you are not extending any class here. You are just using a template. Blaze Components do not extend templates. Blaze Components can extend other Blaze Components.

Yea, you could create a mixin which would that for you. Something like:

class ExposeTemplateHelpersMixin extends BlazeComponent
  mixinParent: (mixinParent) ->
    template = mixinParent.template()
    if _.isString template
      template = Template[template]
    for name of template.__helpers
      name = name.substr(1)
      mixinParent[name] = Blaze._getTemplateHelper(template, name, Template.instance)
    super
mitar commented 9 years ago

Read the text there:

The input template we provided earlier will serve as the markup to be re-used by the component. However, all the helpers and events will be provided through the component class.

mitar commented 9 years ago

Templates do not have any inheritance. They are bunch of HTML + helpers + events. And Blaze Components reuse HTML, but provide their own way of helpers and events (in a different way, a way which can in our opinion has more sense).

mitar commented 9 years ago

So the issue with just copying template helpers over is that you cannot really extend them in a reasonable way. So in OOP way. To extend and call super. Because they work differently than methods.

bartonhammond commented 9 years ago

So when I read this

The input template we provided earlier will serve as the markup to be re-used by the component. However, all the helpers and events will be provided through the component class.

I thought the helpers were inherited as well as the input template.

I will review your comments and figure out where I'm missing it all...seems I've totally misunderstood.

mitar commented 9 years ago

Please do suggest improvements to the text. :-) I do not know how could However, all the helpers and events will be provided through the component class. be understood that helpers are coming from the input template?

bartonhammond commented 9 years ago

Ok - thanks for all your help- I need to review all of this again. Thanks.

mitar commented 9 years ago

So yea. Sorry, but blaze templates are inherently made so that it is hard to reuse them. This is why Blaze Components try to approach things from a different perspective so that you can extend things like you are used in OOP. And this means some legacy stuff is hard to deal with in a consistent way.

bartonhammond commented 9 years ago

I think your 'ExposeTemplateHelpersMixin' is what I'm looking for. Not being a CS guy, I need to work through this.

I get it now that the helpers & events are not passed through. My bad.

bartonhammond commented 9 years ago

Not to belabor this, but conceptually, for me, a Blaze template is a Object or Component - it has a View (the template) and the Controller is the combination of the Helpers and Events. I don't quite understand why the Helpers and Events are thrown away in the Blaze Components implementation. Take for example the "text" Helper implementation for the "useraccounts:core":

    text: function(){
        var key = Meteor.userId() ? AccountsTemplates.texts.navSignOut : AccountsTemplates.texts.navSignIn;
        return T9n.get(key, markIfMissing=false);
    }

Why would this complex behavior be tossed away just because the "View"/template will be changed/replaced? I can't imagine introducing a new component UI implementation of User Accounts if I have to reimplement all this behavior? Anyway, it's your design and it looks like the mixin you proposed should help.

Thanks for all your help. I think Blaze Components will be a key enabler for the work I'm trying to accomplish.

mitar commented 9 years ago

OK, see another possible implementation of text as a Blaze templates helper:

text: function () {
  return this.username;
}

Now, if we expose this as a method call, we cannot just copy this code over, because in Blaze Components, this in methods are component instances, not data context. If we wrap it in something, which mingles the data context, maybe. But then it is a bit strange to extend a helper with a method, where this changes.

Similar for event handlers.

mitar commented 9 years ago

I opened #71.

bartonhammond commented 9 years ago

Thanks very much for the consideration.

Maybe, just an idea, to keep your original vision, you could make available that Mixin capability and see if people actually use it.

For me to continue my research, I'll need it for sure as my focus is changing the view rather then the behavior.

If you could whip that up, I'll test it for you. Otherwise, I'll start writing it now.