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

Customize v-model in components #4515

Closed
Akryum opened this issue Dec 19, 2016 · 4 comments · Fixed by pinterest/teletraan#1117
Closed

Customize v-model in components #4515

Akryum opened this issue Dec 19, 2016 · 4 comments · Fixed by pinterest/teletraan#1117

Comments

@Akryum
Copy link
Member

Akryum commented Dec 19, 2016

A way to change the value and input defaults would be great, especially for ui toolkits.
My use case here is to create a Radio button component that would behave like a standard HTML one:

<ui-radio value="unknown" v-model="answer">I don't know</ui-radio>
<ui-radio value="42" v-model="answer">42</ui-radio>

Here I'd like to change the prop used by v-model to something other that value, like for example a currentValue prop.

Syntax proposal:

export default {
  name: 'ui-radio',

  props: ['value', 'currentValue'],

  model: {
    prop: 'currentValue',
    event: 'input',
  },

  computed: {
    componentClasses () {
      return {
        active: this[this.$model.prop] === this.value,
      }
    },
  },

  methods: {
    handleClick () {
      this.$emit(this.$model.event, this.value)
    },
  },
}
@posva
Copy link
Member

posva commented Dec 19, 2016

I've also come across this when building ui components. We should come up with a way of defining the prop used for the v-model and eventually the event too. I was thinking about the same as @Akryum 🙂

@rpkilby
Copy link

rpkilby commented Dec 19, 2016

Out of curiosity, is there value to overriding the event? If not the syntax could just be:

model: 'currentValue', 

Also, this would probably require component authors to create a computed property for getting the model value, since it would technically be possible to extend the component with a different model name.

computed: {
  modelValue() {
    return this[this.$model]
  }
}

@posva
Copy link
Member

posva commented Dec 20, 2016

@rpkilby We may want to redefine the event for radio/checkboxes inputs that emit change events:

<ui-checkbox @change="doStuff" v-model="visible">Visible</ui-checkbox>

side note: little demo about differents inputs and events: http://jsfiddle.net/posva/oqe9e8pb/

@hidegh
Copy link

hidegh commented Apr 3, 2017

Is there a way in VUE.JS to extend current binding directive to do some pre/post processing? Something like in KnockoutJS - see code below...

$(function () {
    // on document ready...

    if (typeof ko != "undefined" && typeof kendo != "undefined") {
        // Extending original KO handlers to support kendo widgets...since knockout-kendo.js does not worked well in my tests...
        var originalHandlerForValueUpdate = ko.bindingHandlers.value.update;
        var originalHandlerForDisableUpdate = ko.bindingHandlers.disable.update;
        var originalHandlerForEnableUpdate = ko.bindingHandlers.enable.update;
        var originalHandlerForReadonlyUpdate = ko.bindingHandlers.readonly.update;

        ko.bindingHandlers.value.update = function (element, valueAccessor, allBindingsAccessor, viewModel, context) {

            var $element = $(element);
            var value = ko.utils.unwrapObservable(valueAccessor());

            var widget = kendo.widgetInstance($element);
            if (widget != "undefined") {
                // Check if widget has given method, execute it...
                if (widget && widget["value"] !== undefined) {
                    widget["value"](value);
                    return;
                }
            }

            // If binding wasn't processed via kendo widget, use original knockout handler
            originalHandlerForValueUpdate(element, valueAccessor, allBindingsAccessor, viewModel, context);

        };

        ko.bindingHandlers.disable.update = function (element, valueAccessor, allBindingsAccessor, viewModel, context) {

            var $element = $(element);
            var value = ko.utils.unwrapObservable(valueAccessor());

            var widget = kendo.widgetInstance($element);
            if (widget != "undefined") {
                // Check if widget has given method, execute it...
                if (widget && widget["enable"] !== undefined) {
                    widget["enable"](!value);
                    return;
                }
            }

            /*
            if ($element.hasClass('k-textbox')) {
                if (value) $element.addClass("k-state-disabled");
                else $element.removeClass("k-state-disabled");
            }
            */

            // If binding wasn't processed via kendo widget, use original knockout handler
            originalHandlerForDisableUpdate(element, valueAccessor, allBindingsAccessor, viewModel, context);

        };

        ko.bindingHandlers.enable.update = function (element, valueAccessor, allBindingsAccessor, viewModel, context) {

            var $element = $(element);
            var value = ko.utils.unwrapObservable(valueAccessor());

            var widget = kendo.widgetInstance($element);
            if (widget != "undefined") {
                // Check if widget has given method, execute it...
                if (widget && widget["enable"] !== undefined) {
                    widget["enable"](value);
                    return;
                }
            }

            /*
            if ($element.hasClass('k-textbox')) {
                if (value) $element.removeClass("k-state-disabled");
                else $element.addClass("k-state-disabled");
            }
            */

            // If binding wasn't processed via kendo widget, use original knockout handler
            originalHandlerForEnableUpdate(element, valueAccessor, allBindingsAccessor, viewModel, context);

        };

        // We override it only if it was defined before - since readonly binding is a custom handler, we need to do this check
        if (ko.bindingHandlers.readonly !== undefined) {

            ko.bindingHandlers.readonly.update = function (element, valueAccessor, allBindingsAccessor, viewModel, context) {

                var $element = $(element);
                var value = ko.utils.unwrapObservable(valueAccessor());

                var widget = kendo.widgetInstance($element);
                if (widget != "undefined") {
                    // Check if widget has given method, execute it...
                    if (widget && widget["readonly"] !== undefined) {
                        widget["readonly"](value);
                        return;
                    }
                }

                // If binding wasn't processed via kendo widget, use original knockout handler
                originalHandlerForReadonlyUpdate(element, valueAccessor, allBindingsAccessor, viewModel, context);

            };

        };

    } else {
        console.log("ko or kendo is undefined, cannot apply kendo.knockout.bindings.js");
    }

});

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

Successfully merging a pull request may close this issue.

5 participants