vue-material icon indicating copy to clipboard operation
vue-material copied to clipboard

[MdSelect] Can't assign an object to md-option value

Open sunyatasattva opened this issue 7 years ago • 7 comments

Currently, md-option value doesn't accept Objects, which I think is an arbitrary limitation in a web-app.

<md-field>
  <md-select v-model="selectedItem">
    <md-option v-for="item in items" :value="item"> {{ item.name }} </md-option>
  </md-select>
</md-field>

The thing is that, besides throwing a warning because the type Object is not working, this paradigm already works. It doesn't however get shown correctly in the input field because it gets the content from the value instead that from the text content of the node, which is counter-intuitive.

sunyatasattva avatar Jan 30 '18 16:01 sunyatasattva

We know about this, for now you can get your object like this:

Make your select options value as id

This functions are computed For select

getObject () {
      return this.myArrayOfObjects.find((item) => (item.id === this.selectedItem))
},

For multi select

getObjects () {
      return this.myArrayOfObjects.filter((item) => this.selectedItems.includes(item.id))
},

Live example: https://codesandbox.io/s/ww8yzzro3l

Samuell1 avatar Jan 30 '18 17:01 Samuell1

Yes, thank you: that's the workaround I used, actually setting up the data in those computed properties (the model I am trying to access is deeply nested in the object). It's pretty ugly though, but I am glad you guys are aware of it.

The select component is a drag, but it could use many improvements.

sunyatasattva avatar Jan 31 '18 00:01 sunyatasattva

How would I apply this fix to the following?

    '<md-field>'+
        ' <label>{{data.display}}</label>' +
            '<md-select v-model="formInput" md-dense :disabled="enableEdit">' +
             '<md-option :key="option" v-for="(option,index) in choiceCompute" :value="{ID: option.ID, Title: option[data.lookup.field]}">{{option[data.lookup.field]}}</md-option>' +
            '</md-select>' +
    ' </md-field>' +

This works using standard html selects, using md-select when I click an option the data selected is correct but the display text is wrong.

tachiaus avatar Feb 02 '18 00:02 tachiaus

@tachiaus yes because value cant be object, use my computed methods to get your selected object

Samuell1 avatar Mar 12 '18 09:03 Samuell1

@tachiaus @sunyatasattva i forget to mention i edited my last comment and added live example how to use that computed methods

Samuell1 avatar Apr 10 '18 12:04 Samuell1

@Samuell1 any news on this issue?

sunyatasattva avatar Aug 21 '18 18:08 sunyatasattva

@Samuell1 your work around expects, that you can enumerate all the select boxes you are using. So using select boxes in a loop would no longer be possible.

Couldnt one use the following option:

<md-select v-model="getSystemConfigSetter(hc).key" name="systemConfigs" required>
    <md-option v-for="option in options" :value="option.key">{{option.name}}</md-option>
</md-select>

@Component
class XYZ extends Vue {
       public options: Option[];
       public selectedOption: Option;

        public getSystemConfigSetter(hostConfig: HostConfig): SetterByKey<SystemConfig> {
            return new SetterByKey<SystemConfig>(
                () => this.selectedOption,
                (option: Option) => { this.selectedOption = option; },
                this.options,
                (option: Option) => option.key);
        }
}

class Option {
    key: string;
    name: string;
}

// Util once per Project

function ensure<T>(argument: T | undefined | null, message: string = 'This value was promised to be there.'): T {
    if (argument === undefined || argument === null) {
        throw new TypeError(message);
    }

    return argument;
}

class SetterByKey<T> {

    private readonly getValue: () => T;
    private readonly setValue: (newValue: T) => void;

    private readonly options: T[];
    private readonly getKey: (optionType: T) => string;

    public constructor(
        getValue: () => T,
        setValue: (newValue: T) => void,
        options: T[],
        getKey: (optionType: T) => string) {

        this.getValue = getValue;
        this.setValue = setValue;
        this.options = options;
        this.getKey = getKey;
    }

    get key(): string {
        return this.getKey(this.getValue());
    }

    set key(key: string) {
        this.setValue(ensure(this.options.find(option => this.getKey(option) === key)));
    }
}

nheusser avatar May 14 '20 15:05 nheusser