1

I have a strange problem in my Vue application. The component looks like this:

...
<template v-for="foo in foos">
   <Elm v-if="foo.visible" :key="foo.label" :bar="foo" />
</template>
...

"Elm" is a value in an object, retrieved from a JSON file. The component is reactive if I get the JSON file locally:

<script>
    import datas from "datafile.json";
    ...
    methods: {
        fillFoos() {
            datas.forEach(data => {
               this.foos.push(data)
            })
        }
    },
    mounted: {
        this.fillFoos()
   }
   ...
</script>

But when I retrieve the file remotely using fetch, the component is no longer reactive and no longer disappears when the foo.visible value is changed :

<script>
    methods: {
        getDataFromApi() {
            return new Promise((resolve, reject) => {
                fetch(this.apiUrl)
                .then(response => {
                    return response.json();
                })
                .then(jsonResponse => {
                    resolve(jsonResponse);
                })
                .catch(e => {
                    ...
                })
            })
        },
        fillFoos() {
            this.getDataFromApi()
            .then(response => {
                response.forEach(data => {
                    this.foos.push(data);
                });
            });
        }
    },
    mounted: {
        this.fillFoos()
    }
    ...
</script>

In both cases the "foos" array is correctly filled, the only difference is that the v-if directive seems to be broken in the second case. To be more precise, the display is done correctly at initialization (foo.visible is true for all the elements and they're all displayed), but in case of a later change of the foo.visible value, they don't disappear.

I can't find what's wrong...

3
  • In your template tag, where you are using the v-for is that the template tag for a .vue file? Also, can you share the payload that you get when you resolve the promise? Commented Oct 25, 2018 at 21:59
  • The template tag is not the root element of the .vue file (if that's what you meant) Commented Oct 25, 2018 at 22:01
  • You've implemented the explicit promise construction antipattern, don't do that Commented Oct 25, 2018 at 22:40

2 Answers 2

1

I believe the issue you are having is that the method getDataFromApi is returning a promise, but when you consume it in fillFoos the promise is not awaited, instead you call forEach on it.

You need to use the getDataFromApi().then(x => {}) syntax to resolve the promise, or alteratively you can use async await.

You can try something like this

methods: {
    async getDataFromApi() {
        const response= await fetch(this.apiUrl);
        return response.json();
    },
    async fillFoos() {
        try {
            await foos = this.getDataFromApi();
            this.foos = foos;
        } catch(error) {
            //handle error.
        }
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Correct. response.json() is a Promise here, as the body could be streamed.
Sorry, actually i use the then after getDataFromApi, I forgot to write it in the post (now corrected)
Ah! ok ok, can you then show what the ELM component is doing? In your template, i presume you meant <Elm v-if="foo.visible" :key="foo.label" :bar="foo.bar" /> ? note the bar prop.
I pass the whole foo object in the bar v-bind (yes a mistake in my post again !) :bar="foo"
cool, can you show how you are binding to that object inside the component?
|
0

Someone posted a response very close to the solution yesterday but deleted it, I don't know why. The problem was that I stored the fetch response in a variable in the data section, before using it to fill in the "foos" table

data: function() {
    return {
        dataFromApi: null
    }
}

By removing this variable, and thus creating it on the fly after the fetch, everything works normally.... I didn't specify that I stored the answer in this variable because I didn't think it could be related... Morality: always specify everything !

Comments

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.