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

Two-way filter chaining order not called in reverse on write #2447

Closed
jamesstidard opened this issue Mar 12, 2016 · 3 comments
Closed

Two-way filter chaining order not called in reverse on write #2447

jamesstidard opened this issue Mar 12, 2016 · 3 comments

Comments

@jamesstidard
Copy link

You can currently define two-way filters with read and write and you can then chain these filters.

I wrote two two-way filters and chained them:
"... | filterA | filterB"

and on read it calls:
model -> filterA.read -> filterB.read -> display_output

but on write it still calls in the filters in the same order:
display_input -> filterA.write -> filterB.write -> model.

I would expect:
display_input -> filterB.write -> filterA.write -> model.

Am I right to assume that this is a bug or am I misusing the framework?

@yyx990803
Copy link
Member

Hmm, that makes sense, but can you elaborate on the use case? Seeing what you are trying to achieve can help.

@jamesstidard
Copy link
Author

So the use case we had was a moment object on the Vue model and we had two two-way filters on a input field. One to sanitise the user input (e.g. take out non-numeric characters) then a filter which takes that takes a known format and turns in back into a moment object - being able to switch out the sanitiser depending on what user input is expected.

We ended up mixing the two filters into one for now but then also ran across something else related which I'll try and explain as well. It has to do with the expected value of oldValue in the write method.

If we have a single moment representing a date time, and want to give access to it's constituent parts - like hours, minutes and seconds as different input fields to the user. I had initially wrote the write function like this (expecting old_value to be the previous model's moment value):

read: function(value, _, format) {
    return value.format(format)
},
write: function(new_value, old_value, accessor, format) {
    // Make a moment out of the partial user supplied data
    new_partial = moment(new_value, format)

    // if unparsable - keep old value
    if( new_partial.isValid() ) {
        // Use accessor e.g. moment.hours()
        // to get users value out in format expected by setter
        let value = new_partial[accessor]()
        // Modify part of full moment e.g. moment.hours(parsed_hours)
        old_value[accessor](value)
    }

    return old_value
}

Here's an example of how you'd use the filter (display_moment) as well:

<input v-model="some_moment | display_moment 'hours' 'HH'" lazy/>

So this is meant to make a input field which a user can input into and update a specific part of a moment object. As well as when they click away from the input field set it's value to the most recently succesfully parsed value in the correct format.

However, the example about doesn't work as old_value isn't the previous value of the moment object it's about to write to, but the previous value of the users input. So the final filter also accepts a pointer to the model object it can use instead of old_value. So the current bindings look like:

<input v-model="some_moment | display_moment 'hours' 'HH' some_moment" lazy/>
<input v-model="some_moment | display_moment 'minutes' 'mm' some_moment" lazy/>

Hopefully this gives enough context and I've explained it well enough for people to follow while not offended anyone with the unconventional snake_casing in Javascript :).

@yyx990803
Copy link
Member

Write filters should indeed be applied in reverse order (it's fixed now in the above commit).

However, I think the old value is working as intended, because it is supposed to be "the same value from last time this filter is called". Basically instead of expecting old_value to be a parsed moment object and mutating it, you should construct a new moment object out of it.

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

2 participants