ripplejs / ripple

A tiny foundation for building reactive views
http://ripplejs.github.io
1.28k stars 66 forks source link

Firing events/methods when data changes #18

Closed lmartins closed 10 years ago

lmartins commented 10 years ago

Following Anthony's suggestion, im posting this question here since there isn't yet a StackOverflow or forum where this kind of request probably fit better. Hope you don't mind and can point some directions to where look further.

Im trying to build a small component, based on the iteration example, where I have a list of numbers that I can add or remove items.

I've published the working sample here: http://jsfiddle.net/lmartins/VPB93/

Let's say I wanted to achieve the following:

What would you suggest doing to achieve this, I though of custom events or setting an watcher on the items array using the observer plugin but im still lacking the knowledge to figure how all the parts fit together.

anthonyshort commented 10 years ago

I'd probably just use hidden attributes. Let's say the template kinda looks like this

<div each="{{ items }}"></div>
<div hidden="{{ !item.length }}">No items to show</div>

That's probably the easiest way for that.

anthonyshort commented 10 years ago

hidden is a HTML thing, I think IE doesn't automatically set it to display:none though, but you can usually safely add that as a global style

lmartins commented 10 years ago

Thanks for the suggestion Anthony.

But what if I also needed some logic to toggle the state of the "order" and "delete all" buttons, how would you hook that?

Sent from my iPhone

On 26/04/2014, at 19:59, Anthony Short notifications@github.com wrote:

hidden is a HTML thing, I think IE doesn't automatically set it to display:none though, but you can usually safely add that as a global style

— Reply to this email directly or view it on GitHub.

anthonyshort commented 10 years ago

Depends on the sort of logic. If it's just whether there are any items, I'd just do <button disabled="{{ !items.length }}"></button>.

Otherwise if there's more logic around it, you could use computed properties or just listen for changes to the items array.

CustomSMS.created ->
  @data.items.on 'change', =>
    if @data.items.length then @set 'canDeleteAll', true

(My coffeescript might be a little rusty)

The array fires a change event whenever the length changes. So you could check it, and then set a property. Then use that in the template:

<button hidden="{{ !canDeleteAll }}"></button>
lmartins commented 10 years ago

Cool, that gives me a path to explore. The inline properties would do fine for my sample, but my goal here is more to understand how can I wire things up with ripple for future cases.

Thanks again Anthony, I'll close this issue once I'm on my computer.

Cheers.

Sent from my iPhone

On 26/04/2014, at 23:33, Anthony Short notifications@github.com wrote:

Depends on the sort of logic. If it's just whether there are any items, I'd just do .

Otherwise if there's more logic around it, you could use computed properties or just listen for changes to the items array.

CustomSMS.created -> @data.items.on 'change', => if @data.items.length then @set 'canDeleteAll', true (My coffeescript might be a little rusty)

The array fires a change event whenever the length changes. So you could check it, and then set a property.

— Reply to this email directly or view it on GitHub.

lmartins commented 10 years ago

Two quick questions Anthony, 1) Does that created() function supposed to be in the the CustomSMS prototype? 2) Do I need to setup any watcher on the array or it does emit the change events out of the box?

Thank you.

anthonyshort commented 10 years ago
  1. Nope, that's just shorthand for CustomSMS.on('created'... blah blah. But it binds this to the view. That functionality is a little confusing and will probably just be a plugin soon
  2. Nope, when you use the each plugin it turns arrays into event emitters. So you have the .on, .off and .emit methods
lmartins commented 10 years ago

Ok, I think i'll wait for clarification in the docs, while doing some more testing.

I still didn't get it to work, having some scope issues, because the @data.items is returning undefined on the scope it is running. Not sure why because doing a console.log(this) inside the "on" event does return a function View that contains a this.data = this.model.props

Another thing i've noticed, not sure if it is normal, is that the event fires 4 times (1 + 3), apparently what it is happening is that the event fires when the view is first created and then one time for each item in the data.items array.

anthonyshort commented 10 years ago

Within the event handler this will just be the global scope since it isn't bound to anything. That's pretty standard for event emitters. But you get passed a view.

The second one is a bug, I've added it to my list of things to fix up tonight :)

lmartins commented 10 years ago

Ok, im closing this now while im investigating why I can't bind the change to the data.items array.

Thanks for all the help.

anthonyshort commented 10 years ago

Pretty sure the issues you're having are directly related to #21. The each plugin was built pretty quickly and definitely needs some work.

lmartins commented 10 years ago

I believe so, yes, the errors im getting happen on the second time the event fires, which by then is bound to the data.items array iteration and not the the main view.

anthonyshort commented 10 years ago

Yup! It's here https://github.com/ripplejs/each/blob/master/index.js#L45

Need to make that have it's own View rather than re-using the parent one.

lmartins commented 10 years ago

Cool, definitely I'm learning something here despite the frustration of being unable to make it work :-)