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

Question: How would you handle observable extensions ? #5

Open
slaneyrw opened this issue May 28, 2013 · 8 comments
Open

Question: How would you handle observable extensions ? #5

slaneyrw opened this issue May 28, 2013 · 8 comments

Comments

@slaneyrw
Copy link

We use an extender to force type stored in the underlying value ( value binding in text boxes pushes strings into observable ).

How would I wire this up if I was to use ko.track ?

var amount = ko.observable().asInteger(0);

ko.observable.fn['asInteger'] = function (defaultValue) {
    var target = this;
    var interceptor = ko.computed({
        read: target,
        write: function (value) {
            var parsed = parseInt(value, 10);
            var manualNotifyFlag = false;
            if(isNaN(parsed)) {
                parsed = defaultValue;
                manualNotifyFlag = (target() === parsed);
            }
            if(!manualNotifyFlag) {
                target(parsed);
            } else {
                target.valueHasMutated();
            }
        }
    });
    interceptor(target());   // Ensure target is properly initialised.
    return interceptor;
};
@ghost
Copy link

ghost commented Jun 19, 2013

I have the same issue: How is the new syntax to write this?:

result.name = ko.observable(item.name).extend({required: true});

@jods4
Copy link

jods4 commented Dec 10, 2014

You can create an observable on your objects, ko-es5 will turn them into properties just the same.

var obj = { amount: ko.observable().asInteger(0) };
ko.track(obj);
obj.amount = 3;

This code should work.

Or you can use getObservable to grab and configure an underlying observable.

var obj = { amount: 0 };
ko.track(obj);
ko.getObservable(obj, 'amount').asInteger(0);
obj.amount = 3;

Trying to fit this with ko-validation is more difficult because the validation binding handlers expect to receive the observable itself, not his value.

@grofit
Copy link

grofit commented Aug 8, 2015

Did you ever get it working with knockout validation?

I raised a similar sort of question on their board a while back but didnt get an answer:
Knockout-Contrib/Knockout-Validation#550

@jods4
Copy link

jods4 commented Aug 8, 2015

@grofit I did, although it's not very pretty.

I used a binding preprocessor http://knockoutjs.com/documentation/binding-preprocessing.html

A binding preprocessor receives the source text of your binding and you're free to manipulate it anyway that you want.

There are several ways you can go with this. What I did is that I wanted explicit opt-in into validation, so I did this: if the binding text ended with a bang !, in my project it means that validation should be used for this binding. So the preprocessor removed the ! from the binding text and then added a validationCore binding with value ko.getObservable(context,text).

I would then use it like so: <input data-bind='value: amount!' />.

Note that it's been quite some time since I last looked into that. Maybe there's a better way now.

@grofit
Copy link

grofit commented Aug 8, 2015

So the setup is basically a list of ko.getObservable(myVM, myPropertyName).someValidationRule(someValidationProperty);

I assume the asInteger is exposed directly from KO validation? and all other validation rules are exposed as such?

@grofit
Copy link

grofit commented Aug 9, 2015

After playing about a bit here is what I came up with:

<input id="some-value" data-bind="value: amount">

    var vm = {
        amount: 2
    };

    ko.track(vm);

    ko.getObservable(vm, "amount").extend({ min: 3, max: 5});

    ko.getObservable(vm, "amount").isValid.subscribe(function(val) {
       console.log("Is Valid: " + val + " - " + vm.amount);
    });


    ko.applyBindings(vm);

Works fine, although it seems the group and validatedObservable seem to ignore the validation rules.

@jods4
Copy link

jods4 commented Aug 9, 2015

@grofit That was pretty much my setup, except that I used a helper function to declare validation rules easily. It was used something like this:

var vm = { amount: 2, name: 'jods' };
ko.track(vm);
setupValidation(vm, { amount: { min: 3, max: 5 }, name: { required: true } });

For group and validatedObservable I don't think I used them. But at the core the problem is the same: they read object properties hoping to find an observable and get a value.

I think you have three options to make those things work:

  1. Fork or monkey patch those functions (really ugly).
  2. Automatically create properties that grant access to the underlying observable, e.g. get amount$obs() { return ko.getObservable(this, 'amount') } and pass those instead to functions that want to fiddle with observables.
  3. Set everything up before calling ko.track.
var vm = { 
  amount: ko.observable(2).extend({ min: 3, max: 5 }) 
};
// call `group` and `validatedObservable` if you want to.
// Then:
ko.track(vm);

@grofit
Copy link

grofit commented Aug 10, 2015

Yeah I am currently just making a custom object to check over the isValid stuff. The latter option is not really an option here as I am trying to get away from the ko.observable calls.

Thanks for info though.

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

No branches or pull requests

3 participants