I'm at the beginning of making a simple one page photo steam app with the public Flickr stream, but with what i've done so far i'm getting the error
'Cannot set property 'data' of undefined'.
My code:
<b-container>
<b-row>
<b-col>
<p md="4" v-for="photo in Photos">{{photo.id}}</p>
</b-col>
</b-row>
</b-container>
</template>
<script>
import jsonp from "jsonp";
export default {
name: 'PhotoFeed',
data: function() {
return {
Photos: [],
apiURL: "https://api.flickr.com/services/feeds/photos_public.gne?format=json"
}
},
mounted(){
this.getFlickrFeed();
},
methods: {
getFlickrFeed(){
let jsonp = require('jsonp');
jsonp(this.apiURL, {name:'jsonFlickrFeed'}, function(err,data) {
this.data = data;
var self = this;
if (err){
console.log(err.message);
}
else {
this.Photos = self.data;
}
});
}
}
}
</script>
You want var self = this to be outside the anonymous function definition so this keyword is not shadowed by the new function;
getFlickrFeed () {
let jsonp = require('jsonp');
var self = this; // now self refers to the vue component and can
// access the Photos property in data
jsonp(this.apiURL, { name:'jsonFlickrFeed' }, function (err,data) {
if (err){
console.log(err.message);
}
else {
// also use self.Photos to refer to the Vue component
self.Photos = data;
}
});
}
The simplest is to use an arrow function instead of an anonymous function:
jsonp(this.apiURL, { name:'jsonFlickrFeed' }, (err, data) => {
if (err) {
console.log(err.message);
}
else {
this.Photos = data;
}
})
You could use arrow function ()=> and use this in the callback context as follows :
jsonp(this.apiURL, {name:'jsonFlickrFeed'}, (err,data)=> {
this.data = data;
if (err){
console.log(err.message);
}
else {
this.Photos = this.data;
}
});
Related
I have multiple function with the same default parameters for all of it.
Is there somehow to add default parameters for all of it without copying and paste?
// 1st function
export function modify(id, values, failCB = (err) => error("π« Error"), successCB = () => success("β Success")) {
//...
if (err) {
failCB(err.message);
} else {
successCB()
}
}
// 2nd function
export function remove(id, failCB = (err) => error("π« Error"), successCB = () => success("β Success")) {
//...
if (err) {
failCB(err.message);
} else {
successCB()
}
};
You can declare variables that store the default value of the parameters and refer those variables instead:
const defaultCbIfFailed = err => error("π« Error");
const defaultCbIfSuccess = () => success("β Success");
//1st function
export function modify(id, values, failCB = defaultCbIfFailed, successCB = defaultCbIfSuccess) {
//...
if (err) {
failCB(err.message);
} else {
successCB()
}
}
// 2nd function
export function remove(id, failCB = defaultCbIfFailed, successCB = defaultCbIfSuccess) {
//...
if (err) {
failCB(err.message);
} else {
successCB()
}
};
Use function declarations for your callbacks and pass references to those:
// 1st function
export function modify(id, values, failCB, successCB) {
//...
if (err) {
failCB(err.message);
} else {
successCB()
}
}
// 2nd function
export function remove(id, values, failCB, successCB) {
//...
if (err) {
failCB(err.message);
} else {
successCB()
}
};
function failCB = (err) => error("π« Error")
function successCB = () => success("β Success")
I knew what Shrihan answered. What I actually want is something like this
removeSubject.parameters = failCB;
I am trying to fetch data through Axios' request and push into an array. Here is my code:
props: [
'products',
],
data: function () {
return {
algolia: '',
products_data : [],
};
},
mounted() {
this.products_data = this.products;
}
methods: {
find () {
let new_product = {};
axios.get('/product/find?barcode=' + this.barcode)
.then(function (res) {
new_product.name = resp.data.name
new_product.barcode = resp.data.barcode
new_product.unit = resp.data.unit
this.products_data.push(new_product);
})
.catch(function (err) {
console.log(err);
})
},
}
I am getting the error Cannot read property 'products_data' of undefined sue to this line this.products_data.push(new_product); I am new in Vue. Any help would be highly appreciable.
Regards
this should work, i have removed function syntax and used arrow function.
find () {
let new_product = {};
axios.get('/product/find?barcode=' + this.barcode)
.then((resp) => {
new_product.name = resp.data.name
new_product.barcode = resp.data.barcode
new_product.unit = resp.data.unit
this.products_data.push(new_product);
})
.catch((err)=> {
console.log(err);
})
}
When I try to use this in my VueJs methods I get the following error
this is undefined
I think that I shouldn't use arrow functions because their this does not bind to the context I expect it to.
I try with a regular function and get the error above.
What I've tried so far
methods: {
connection(){
new elasticsearch.Client({...});
client.search({...})
.then(function (resp) {
var hits = resp.aggregations;
this.tmp = hits[1].value;
}, function (err) {
console.trace(err.message);
});
}
}
I cannot use the this that I want to in the functions passed to .search and .then . How can I have this bind to my VueJs instance so I can access data, computed, etc...?
You should use arrow function to save this context, and don't forget that inside Vue methods this refers to the current instance.
data() {
return {
counter:0,
connections:2,
tmp: 0,
}
},
methods: {
connection() {
// ...
var client = new elasticsearch.Client({
host: 'xxxxxxxxxxxx'
});
client.search({
[...]
}).then((resp) => {
var hits = resp.aggregations;
this.tmp = hits[1].value;
}, (err) => {
console.trace(err.message);
});
}
}
You can assign this variable to local variable(self) and use it in .then function
data () {
return {
counter:0,
connections:2
}
},
methods: {
connection(){
var self = this;
var tmp=0
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: 'xxxxxxxxxxxx'
});
client.search({
"index":"400000",
[...]
}
}).then(function (resp) {
var hits = resp.aggregations;
self.tmp=hits[1].value;
}, function (err) {
console.trace(err.message);
});
console.log("tmp:",tmp)
}
}
Why is the output of the piece of code below "true"?
class InstagramGallery extends React.Component {
constructor(props) {
super(props);
this.state = {
images: true
};
}
componentDidMount() {
var accessToken = '*Instagram token*';
var instagramApi = new Instagram(accessToken);
instagramApi.userSelfMedia().then(function(result) {
this.setState({
images: false,
});
}, function(err) {
console.log(err);
});
}
render() {
console.log(this.state.images);
return (
<div className="instagram-gallery">
</div>
)
}
}
From what I know, the constructor is being called first. Therefore images=true, after that it renders with console.log(true), and componentDidMount is called. After data from instagram is fetched, and I update component state which should re-render the component with images=false. Where am I wrong?
You are using a regular function for instagramAp.userSelfMedia callback hence losing this context. Use an arrow function instead:
instagramApi.userSelfMedia().then(
result => {
this.setState({
images: false
});
},
function(err) {
console.log(err);
}
);
Regular functions create their own lexical scope, so this does not point your class in the callback function. Arrow functions don't create their own lexical scopes, to this points your component and you can use this.setState().
Using an arrow function saves you from binding your function or keeping this in another variable like:
var accessToken = "*Instagram token*";
var instagramApi = new Instagram(accessToken);
const that = this;
instagramApi.userSelfMedia().then(
function(result) {
that.setState({
images: false
});
},
function(err) {
console.log(err);
}
);
I've not been using RN for that long but does this have an affect?
componentDidMount() {
var accessToken = '*Instagram token*';
var instagramApi = new Instagram(accessToken);
instagramApi.userSelfMedia().then((result) => { //USING ARROW FUNCTION
this.setState({
images: false,
});
}, function(err) {
console.log(err);
});
}
I added an arrow function so that the 'this.state' doesn't get mixed up with the 'this' inside instagramApi.userSelfMedia().
Because this isnβt available
Use arrow function
instagramApi.userSelfMedia().then((result) => {
this.setState({
images: false,
});
}, function(err) {
console.log(err);
});
}
Or bind it manually
instagramApi.userSelfMedia().then(function(result) {
this.setState({
images: false,
});
}.bind(this), function(err) {
console.log(err);
});
}
I've a Vue component as follows:
import '../forms/form.js'
import '../forms/errors.js'
export default{
data(){
return{
form: new NewForm({
email: '',
password: '',
intendedUrl: '',
message: ''
})
}
},
methods: {
/**
* Login the user
*/
login(e) {
e.preventDefault();
this.form.startProcessing();
this.$http.post('/login/authenticate', this.form)
.then(function(response) {
this.form.finishProcessing();
},
function(response) {
this.form.setErrors(response.data);
});
}
}
}
The form.js file is
window.NewForm = function (data) {
var form = this;
$.extend(this, data);
this.errors = new NewFormErrors();
this.busy = false;
this.successful = false;
this.startProcessing = function () {
form.errors.forget();
form.busy = true;
form.successful = false;
};
this.setErrors = function (errors) {
console.log('okkk');
form.busy = false;
form.errors.set(errors);
}
};
and error.js
window.NewFormErrors = function () {
this.errors = {};
this.set = function (errors) {
console.log(errors);
this.errors= errors;
};
};
Here, the this.form.startProcessing(); seems working. But I'm not able to get the data passed to the this.setErrors. console.log(errors) returns nothing. Or it's not getting executed.
I have not recreated all of your solution but I will suspect the meaning of the value of this in the deferred execution so I will try to modify the code to:
login(e) {
e.preventDefault();
var that = this ;
this.form.startProcessing();
this.$http.post('/login/authenticate', this.form)
.then(function(response) {
that.form.finishProcessing();},
function(response) {
that.form.setErrors(response.data); });
}
I hope it will help.