Alternative way of handling undefined ajax data - javascript

Something I have never truly understood in Vue is how one should tackle the issue with undefined "network/async keys".
Give the example below:
<template>
<div>
<h1>{{row.something_undefined_before_ajax_returns.name}}</h1>
</div>
</template>
<script>
export default {
data() {
return {
row: {}
}
},
created() {
axios.get('.../row/12')
.then(response => {
// response = {data: {something_undefined_before_ajax_returns: {name: 'John Doe'}}}
this.row = response.data
})
}
}
</script>
This would return in a console warning of: [Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined". However, the h1 will finally display John Doe once Vue registered the async changes.
However, the way I have coped with this 'til now is to simply define the expected key in the js like so:
<script>
export default {
data() {
return {
row: {
something_undefined_before_ajax_returns: {}
}
}
},
...
}
</script>
By doing that, Vue does not throw a warning as expected. However, this does work in the short term, but once the return data from the HTTP calls gets a bit more complex and nested, this feels really pointless having to define all the possible outcomes.
Is there a way to tell Vue to ignore such warnings until the call has been received?

You can simply use v-if:
<h1 v-if="row">{{row.something_undefined_before_ajax_returns.name}}</h1>
And you may also check row property:
<h1 v-if="row && row.something_undefined_before_ajax_returns">
{{row.something_undefined_before_ajax_returns.name}}
</h1>
Sorry, I din't notice that row is an object, to check it you may use like:
v-if="Object.keys(row).length"
But I don't think you need to check for object but its property, so you can do just:
v-if="row.something_undefined_before_ajax_returns"

Related

How to redirect in Nuxtjs when the return query of Graphql is empty

I'm very new to Nuxtjs and javascript world. The Nuxtjs project I'm working on required fetching data from Backend (Strapi) using Graphql.
The goal is to make a redirect to homepage (index.vue) when Graphql return empty query result.
However, it did not work when I'm using router.push('/') as the code below.
Please note that I'm trying to redirect both on result and mounted block. Both of them did not work at all.
Please help me point out what I'm doing wrong here. Thank you for your kindness in advance
<script>
import getProfiletQuery from '~/apollo/queries/profiles/profile'
export default {
data () {
return {
profiles: {
}
}
},
apollo: {
profiles: {
prefetch: true,
query: getProfiletQuery,
variables () {
return { user: this.$route.params.user }
},
result ({ data }) {
if (data.profiles.length === 0) {
console.log('it enters here!!!')
this.$router.push('/') //this is not working
}
}
}
},
mounted () {
console.log('this.profiles.length: ', this.profiles.length)
if (this.profiles.length === 0) {
this.$router.push('/')
}
}
}
</script>
Old question, but the replies weren't helpful at all and no answers were offered. So in case you never found the answer, here's the best way I know of personally.
The reason your intended method didn't work is because it's unexpected behaviour for the Nuxt router. This is explained in much more detail here:
vue-router — Uncaught (in promise) Error: Redirected from "/login" to "/" via a navigation guard
There are some possible workarounds listed there, but don't use them in this use case.
What you want to do instead, is throw an error, then let Nuxt's built-in error handling take over.
Inside your result(), you need to properly call a Nuxt error like so:
result ({ data }) {
if (data.profiles.length === 0) {
this.$nuxt.error({ statusCode: 404, message: 'Page not found.' })
}
}
Then, you will need to ensure you have an error.vue template file inside your /layouts/ directory. This should contain at a bare minimum:
<template>
<div class="container">
<h1>{{ error.statusCode }}</h1>
<h2>{{ error.message }} </h2>
</div>
</template>
Sorry I didn't see this earlier, and hope you got something working in the meantime! At least now there is an answer there for whoever comes looking next!

Data is vanished in next line

Can anyone please explain me what is happened in these codes and how can I solve it?
I get the data in the parent's mounted function and update its data. So I have the new object in the child. But the value of the property of this object is empty!
Parent:
<template>
<div class="main-page">
<main-content v-bind:config="mainContentConfig" />
</div>
</template>
mounted(){
fetchData().then(editions => { editions.sort((e1, e2) => e1.name.toLowerCase().localeCompare(e2.name.toLowerCase()))
this.mainContentConfig.intranetEditions = [...editions];
this.mainContentConfig.currentMenuIndex = 1;
});
}
Child:
mounted(){
console.log("AA==============>", this.config);
console.log("BB==============>", this.config.intranetEditions);
}
But on the console I have:
I found this problem when I fill other data in the child class with this.config.intranetEditions array which always is empty!
Edit:
I tried this code too, but no difference!
[...this.config.intranetEditions]
Edit 2 This code tested too, but nothing!
console.log("AA==============>", this.config);
console.log("BB==============>", JSON.stringify(this.config.intranetEditions));
The child-component is mounted but the parent fetch is not finished yet, so this.config is an observer until the fetch is done (so the then is fired) and the var fulfilled.
Can you try to watch the prop config in the child-component? then you will see when this.config is fulfilled.
https://v2.vuejs.org/v2/guide/computed.html#Watchers
UPDATE WITH EXAMPLE:
child-component
watch: {
config(newValue) {
console.log("AA==============>", newValue.intranetEditions);
checkConfigValue();
},
},
methods: {
checkConfigValue() {
console.log("BB==============>", this.config.intranetEditions);
};
},
So you can wether do something in the watcher with the newValue, or trigger a method and use this.config. Both consoles, will print the same in this case.

Vue-Snotify notification is not showing up

I must implement the library Vue-Snotify to show notifications in a Vue.js project.
Notice: I have no pre-experience with Vue.js! I just got this task and it needs to be done.
I have played around with the project and tried different approaches, which got me to understand Vue.js a bit better but after trying so much, I'm left with no idea how to fix this :(
home.js
import Snotify from 'vue-snotify'
Vue.use(Snotify)
var vmHome = new Vue({
...
components: {
myFancyComponent,
...
}
})
myFancyComponent.vue
<template>
<div>
<button type="button" #click="showNotif">Show</button>
<vue-snotify></vue-snotify>
</div>
</template>
<script>
module.exports = {
name: "my-fancy-component",
methods: {
showNotif: function() {
console.log(this.$snotify.success('Example body content'))
}
},
...
}
</script>
I can trigger the notification method and it even returns me a valid object - no errors! But no trace of a notification.
SnotifyToast {id: 338737384058, title: null, body: "Example body content", config: {…}, eventEmitter: Vue$3, …}
Though I noticed an error in the console on the page's first load:
[Vue warn]: Error in created hook: "TypeError: Cannot read property 'emitter' of undefined"
found in
---> <VueSnotify>
<MyFancyComponent>
<Root>
TypeError: Cannot read property 'emitter' of undefined
at VueComponent.created
I wonder why the VueSnotify tag wraps the MyFancyComponent and not the other way around?
It seems that you got the methods data type wrong, it needs to be an object and not array.
module.exports = {
name: "my-fancy-component",
//---------v--- This part
methods: {
showNotif: function() {
console.log(this.$snotify.success('Example body content'))
}
},
...
}

How to send variable as a parameter to a method in single file component?

I am trying to replace all \n with <br> in a variable. Why I can't send variable as a function parameter to a method from template? Console says Uncaught TypeError: Cannot read property 'replace' of undefined.
I think it calls n2br method but can't send variable as a parameter.
Can anybody know how to solve this problem?
<template>
<div id="iletisim" class="page">
<div>{{ n2br(iletisim.address) }}</div>
</div>
</template>
<script>
export default {
name: "iletisim",
data() {
return {
iletisim: ""
}
},
methods: {
fetch: function() {
this.$http.get(this.site.apiPath + this.site.currentLangCode + "/" +this.$route.params[1]).then(response => {
this.iletisim = response.body.content;
},
response => {
// error callback
});
n2br: function(text) {
text = text.replace(/(?:\r\n|\r|\n)/g, '<br />');
return text;
}
},
beforeMount () {
this.fetch()
}
}
</script>
When this is initially instantiated your 'iletism' data is a string. The string does not have a property of address. So iletism.address is undefined.
When that arrives to your n2br function it calls undefined.replace. Which does not exist, hence the replace does not exist on undefined error.
So either guard for this in n2br method or set a default for iletism so that address exists but is empty string.
You could accomplish same thing with a computed property but same will be true that you will need a base case that is set in data or in the computed method.
Hmm I don't think you need to send it honestly. Sounds like you need a computed property.
Lets say your fetch method sets data property iletisim.
In your template you would do this:
<div>{{ computedIletisim }}</div>
And then in your component after methods add computed
export default {
...
methods: {
...
},
computed: {
computedIletisim: function() {
return this.iletisim.address.replace(/(?:\r\n|\r|\n)/g, '<br />');
}
}
...
}

meteor + react "Uncaught TypeError: Cannot read property 'data' of undefined"

Im using Meteor + React and "this.props.thing.source" is a string for a mongodb _id.
The "findOne()" function is one of Meteor's. As you can see it works fine when I pass in the string of the ID itself, but I get an undefined error when passing in the variable, even though that variable renders out that same string.
In this code:
Thing = React.createClass({
propTypes: {
thing: React.PropTypes.object.isRequired
},
render() {
return (
<ul>
<li>Display: {Things.findOne(this.props.thing.source).data}</li>
<li>Display: {Things.findOne("emq6M4WbJeRvkA6Q3").data}</li>
<li>Source: {this.props.thing.source}</li>
</ul>
);
}
});
This does NOT work:
Display: {Things.findOne(this.props.thing.source).data}
This works:
Display: {Things.findOne("emq6M4WbJeRvkA6Q3").data}
And this correctly renders "emq6M4WbJeRvkA6Q3":
Source: {this.props.thing.source}
The ERROR I am getting:
"Uncaught TypeError: Cannot read property 'data' of undefined"
You're getting the error because of whatever Things.findOne() returns is undefined.
You say that calling above function with the this.props.thing.source does not work, which is wrong but since you're not mentioning how the rendering of your Thing component takes place your best bet to find the error is the way you're passing the prop this.props.thing.source/what you're passing to your component.
I made a quick copy-paste example that illustrates and also made your component work in a JSFiddle
var Things = {
findOne: function (thingSource) {
if (thingSource) {
return {
data: 'It did work!'
};
}
return undefined;
}
}
var Thing = React.createClass({
propTypes: {
thing: React.PropTypes.object.isRequired
},
render: function() {
return <div>Hello {Things.findOne(this.props.thing.source).data}</div>;
}
});
React.render(<Hello thing={{source: true}} />, document.body);
A working example with your exact component can be found here

Categories