I'm trying to create a simple plugin in Vue.js to wrap the vue-resource
plugin to track the state of a request.
function State() {}
State.prototype.post = function (ctx, name, url, data, successCB, errorCB) {
var options = {};
if (errorCB) {
options.error = function (resp) {
ctx[name] = 'error';
return errorCB(resp);
};
}
ctx[name] = 'sending';
ctx.$http.post(url, data, function (res, code, req) {
ctx[name] = 'sent';
return successCB(res, code, req);
}, options);
};
function install(Vue) {
Object.defineProperties(Vue.prototype, {
$state: {
get: function () {
return new State;
// return Vue.state.bind({$vm: this});
}
}
});
}
module.exports = install;
You will see I pass the ctx
context from the calling Vue to get access to it's data
values. I've seen with the vue-resource
plugin that there is a way to automatically bind this through the plugin bat can't quite get the syntax right.
Basically I would like to avoid having to pass the ctx
context in each time, it should just have the proper context already.
EDIT
To clarify I'm looking for a solution to pass the proper context in. The above is just sort of an example and I'm not looking for a solution to track states.
For example in the vue-resource
plugin if we make any http request.
this.$http.get('/some/url', {}, function () {
this.func();
console.log(this.var);
});
The context is already there in the callback. I don't need to do some kind of var _this = this
to get into the views scope. I want to achieve the same for my plugin so that the proper this
is just there. I'm trying to figure it out from the vue-resource
plugin but having a hard time following all the code.
Expanding my comment to an answer -
So you have a name
property on your Vue component, and you want this plugin to update that value as the HTTP request progresses? I think that gives you a bad chain of responsibility. Your Vue instance would be required to have a name
property, and your plugin wouldn't be standalone.
It would be better to make the plugin handle all state-tracking on its own. You could make a property of State called status
that is updated as the request progresses. Then you could know the current state using this.$state.status
. Then the plugin is responsible for it's purpose, and the component remains independent
State.prototype.status = "not sent";
State.prototype.post = function (url, data, successCB, errorCB) {
var options = {};
if (errorCB) {
options.error = function (resp) {
this.status = 'error';
return errorCB(resp);
};
}
this.status = 'sending';
this.Vue.http.post(url, data, function (res, code, req) {
this.status = 'sent';
return successCB(res, code, req);
}, options);
};
function install(Vue) {
Object.defineProperties(Vue.prototype, {
$state: {
get: function () {
var state = new State;
state.Vue = Vue;
return state;
}
}
});
}
Then in html:
<div v-if="$state.status == 'sending'">Sending...</div>
<div v-if="$state.status == 'sent'">Sent!</div>
<div v-if="$state.status == 'error'">Error!</div>
If you do want to do things your way, I think you'd just need to bind this
to post()
each time from within your Vue component:
this.$state.post(args){
}.bind(this)
So within the post
function this
would be your Vue. I think the first way is best
Edit --
The functions successCb
and errorCb
are already run in the scope of the Vue component, because you defined them there. The vue-resource
callbacks in your situation have the scope of State
because you defined them here, that isn't going to change unless you pass the context in as you've done. But the point here is that your plugin should not need to know the context of the component, just as vue-resource
never knows the context of the component. It just gets the data, sends the request, and runs the callback. Never knows anything about the calling component.
So in the functions you send to this.$state.post
as callbacks, you can edit your Vue data using this.var
- as you should be able to. In the callbacks you send to Vue.http.post
from your State, you can edit properties on the State
object - again, expected behavior. You need to make the name
or status
variable a part of State
and then reference it as this.$state.name
from within your Vue component to check the status.
edit 2:
you could even have a variable $state.response
and pass in myCustomVar
, and then track $state.response.myCustomVar
. That way you could pass in different custom variables on each request and track them independently
I ended up sorting this out, it was easier than I thought.
It's just a simple shortcut wrapper around the $http
method in the vue-router
so that calls can be made like so:
this.$state.get('/buildings', data, function (resp) {
this.buildings = resp.data;
}, {
track: 'getBuildingState'
});
Or
this.$state('/buildings', {
data: data,
track: 'getBuildingState',
success: function (resp) {
this.buildings = resp.data;
}
});
Can check out the snippet on Gihub here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With