0

A little background on the problem

I've built a custom system to automatically watch some "store" properties that comes from a JSON of a nosql database. Nothing too complicated except the nesting (required for several reasons not discussed here) of objects.

The data structure looks like this:

{
    store: {
        objA: {
            objB: {
                prop1: 'some value'
            }
        }
    }
}

However, since it's a nosql database that provide that store property, objB can just be NOT present after the load from the database.

Example of the template used

I have custom components that have props bound directly to that data store

<my-selector :value.sync="store.objA.objB.prop1">
</my-selector>

However, it crashes when "objB" is not present with the usual javascript error saying that it cannot get "objB" of undefined, but that is normal.

I'm trying to find a vuejs way to prepare the data for me.

Ideas

In order to counter that crash :

  • I can NOT use v-if in that case to mask the selector. Because that selector can be used even if the data is not yet set (example: for optional data).
  • I could fix the "load" function that gets the data from the database so it initialize the required properties (like objB) before assigning data to the data store. However, that would imply that my initial VueJS data object would contain these required properties as well. It's probably that I will use if I can't find any alternative solution, but I don't think that's the easiest way around because I would have to fix any incoming data before assignment.
  • My preferred choice would be to create a directive (or any other thing built in the template) that would add them for me if they are missing.

VueJS always evaluates the bindings value

I thought of that solution:

<my-selector v-autocreate="'store.objA.objB.prop1'" :value.sync="store.objA.objB.prop1">
</my-selector>

However the directive binding "v-autocreate" is not picked up first (checked with the debugger). I did not find documentation relative of the order of load of directives or attributes.

I was also hoping to get all bindings of a node with the directive "bind" function in order to NOT repeat the string, but it seems we can't get that information (I'm used to knockoutjs where we can pick all bindings assigned to a node in order to behave differently).

I would like to reach that goal but I'm not sure that it's possible (I would need something like a pre-bind / beforeBind event on directive haha) :

<my-selector v-autocreate :value.sync="store.objA.objB.prop1">
</my-selector>

Where v-autocreate would assure to do the vm.$set of the missing properties.

2

1 Answer 1

1

You could create a method that checks each property in an object path, creates it if it doesn't exist, then returns the value of the last property.

Example (not tested):

get(object, path) {
    path = path.split('.')

    let index = 0
    const length = path.length
    let val
    while (object != null && index < length) {
        let key = path[index++]
        if(object[key] == null) {
            this.$set(object, key, {})
        }
        object = object[key]
    }
    return val
}

Usage:

<my-selector :value="get(store,'objA.objB.prop1')">
</my-selector>

You may be interested in lodash's get function, which is what the code example is based on.

https://github.com/lodash/lodash/blob/master/get.js

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks but Webpack "vue-template-es2015-compiler" crashes when attempting to use a method inside a property. So it doesn't work. I don't know if it works with pure VueJs but I wanna use .vue files + webpack.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.