Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mixins. This could be an easy thing to implement #536

Closed
emehrkay opened this issue Mar 25, 2015 · 8 comments
Closed

Mixins. This could be an easy thing to implement #536

emehrkay opened this issue Mar 25, 2015 · 8 comments

Comments

@emehrkay
Copy link
Contributor

I was playing around with the idea of having mixins with the tags because I found myself need that kind of functionality. I took a look at the compiler and it would only take a few changes to make it happen.

In the compiler we simply return this in the mktag function

      function mktag(name, html, css, js) {
        return 'riot.tag(\''
          + name + '\', \''
          + html + '\''
          + (css ? ', \'' + css + '\'' : '')
          + ', function(opts) {' + js + '\n return this \n});'
      }

Then in the Tag constructor, you'd simply set that return to a temp variable when mounting

    // initialiation
    //fn && fn.call(self, opts) // existing code
if (fn){
  var func = fn.call(self, opts)
  if('mixins' in func){
    each(func.mixins, function(mix){
      extend(self, mix)
    })
    delete func['mixins']
  }
}

And finally in you define your mixin (object literal) and tag and finally mount it all

    <test></test>
    <script>
    var Mixin = {
        'some_member': 'some mixin value',

        alertFromMixin: function(){
            alert(' alert from mixin')
            console.log(this)
        }
    }
    riot.mount('test')
    </script>

<test>
    <div>
        <a href="#" onclick={ alertFromMixin }>should trigger mixin</a> 
        <a href="#" onclick={ otherFunc }>interal</a>
    </div>

    <script>
        this.mixins = [Mixin]

        otherFunc(){
            alert('from definition '+ this.some_member)
        }
    </script>
</test>

This approach allows for multiple mixins

    <test></test>
    <script>
    var Mixin = {
        'some_member': 'some mixin value',

        alertFromMixin: function(){
            alert(' alert from mixin')
            console.log(this)
        }
    }

    var SecondMixin = {
        fromSecond: function(){
            alert('alert from second mixin')
        }
    }
    riot.mount('test')
    </script>

<test>
    <div>
        <a href="#" onclick={ alertFromMixin }>should trigger mixin</a> 
        <a href="#" onclick={ otherFunc }>interal</a> 
        <a href="#" onclick={ fromSecond }>second mixin</a>
    </div>

    <script>
        this.mixins = [Mixin, SecondMixin]

        otherFunc(){
            alert('from definition '+ this.some_member)
        }
    </script>
</test>

What do you all think?

@GianlucaGuarini
Copy link
Member

You have access ti the window properties inside your tags so you can just use it to share your mixins accross several views

<script>
window.myMixins = {
  hello: function() { return 'hello'; }
}
</script>
<test>
    <div>
        <a href="#" onclick={ window.myMixins.hello }>should trigger mixin</a> 
        <a href="#" onclick={ otherFunc }>interal</a> 
        <a href="#" onclick={ fromSecond }>second mixin</a>
    </div>
</test>

@emehrkay
Copy link
Contributor Author

That doesn't solve the problem. In my example the mixin's members becomes members of the Tag instance.

I modified the source and put it up as an example. If you click "second mixin" you'll see that it has access to the tag's methods. Those methods are also passed around with the tag instance, whereas the global ones are not.

http://jsfiddle.net/8tqfn0rn/1/

You'll get an alert right away and an error. The error is from trying to call the global mixin on the tag instance. The alert is from calling the mixed in method on the instance.

@emehrkay
Copy link
Contributor Author

Here is a better example:

http://jsfiddle.net/8tqfn0rn/4/

@eyy
Copy link

eyy commented Mar 26, 2015

What about Object.assign(this, mixin, mixin)?

EDIT: Or event better, give the mixin access to the tag events

function myMixin (tag) {
  tag.on('unmount', ...)
  tag.msg = 'hi there'
}
function anotherMixin (tag) {
  tag.on('update', ...)
}
riot.tag('timer', '<span>{ msg }</span>', function(opts) {
  myMixin(this)
  aontherMixin(this)
  // or
  [ myMixin, anotherMixin ].map(m => m(this))
})

@emehrkay
Copy link
Contributor Author

Object.assign isnt widely supported, you'd need a shim. Whereas what I did to Tag.mount is clone the mixin and add its members to the Tag instance.

Your second approach would require a lot from the developer. Im not saying that is a bad thing, but Riot is simple, which is what I love about it, but your approach has given me an idea. What if the tag simply supplies a mixin method that takes an array of objects to fold in

//inside Tag

this.mixin = function( mixins ){
  each(mixins, function(mix){
      extend(self, mix)
    })
}

Then in your tag definition, you simply call it (just like your map example)

<tag>
    <html><some html ...></html>

    this.mixin([FirstMixin, SeconMixin, ...])
</tag>

I like this new approach more. Existing tag definitions wouldn't need to be updated and we still get the mixin behavior

I like the Tag constructor providing a mixin member. Same example as above

http://jsfiddle.net/8tqfn0rn/5/

@emehrkay emehrkay mentioned this issue Apr 14, 2015
@GianlucaGuarini
Copy link
Member

@emehrkay why don't you make a pull request with some tests?

@emehrkay
Copy link
Contributor Author

I'll do it this weekend

Sent from my iPhone

On Apr 24, 2015, at 4:40 PM, Gianluca Guarini notifications@github.com wrote:

@emehrkay why don't you make a pull request with some tests?


Reply to this email directly or view it on GitHub.

@cognitom
Copy link
Member

cognitom commented May 8, 2015

I've started to use mixin in riot-bootstrap and realized it's useful 👍
https://github.com/cognitom/riot-bootstrap/tree/dev

It seems more convenient if Riot.js has the way to share the mixins in the application. For example:

// my-mixin.js
riot.mixin('myMixin', {
  message: 'Hello!'
})
// my-tag.tag
<my-tag>
  <p>{ message }</p>
  this.mixin('myMixin')
</my-tag>

@tipiirai How about?

UPDATE: slightly changed the code and made PR about this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants