Vue.js 2.0 - Passing arguments in methods AJAX Axios - ajax

I need to pass an arguments in methods using ajax axios.
var app = new Vue({
el: '#app',
data: {
urlAdmission:
admissions: [
{ name : 'asdf'},
{ name : 'sd'}
]
},
mounted: function(){
this.allAdmissions()
},
methods: {
allAdmissions: _.debounce( function(){
var app = this
axios.get('http://localhost/school/api/hello')
.then( function(response ){
app.admissions = response.data.admissions
})
.catch( function(error){
console.log(error)
})
})
}
});
As you can see in mounted I call the methods this.allAdmissions() I need to pass an argument so that I can reuse the function. For example this.allAdmissions('http://localhost/school/api/hello'). Then use it in axios.get('url'). Thanks

It looks like what you're trying to do is make a function that can accept a url and bind the results of the url to a variable value in your data. Here is how you might do that.
methods: {
allAdmissions: _.debounce(function(url, value){
axios.get(url)
.then(function(response){
this[value] = response.data.admissions
}.bind(this))
.catch(function(error){
console.log(error)
})
})
}
Then, if you call that method like this,
this.allAdmissions('http://localhost/school/api/admissions‌​', "admissions")
allAdmissions will set the admissions property on your data to the result of your call. This works if you always want to use response.data.admissions because you hardcoded that. If you wanted that to be variable as well, you might pass in a third value like so
methods: {
getSomeData: _.debounce(function(url, value, responseValue){
axios.get(url)
.then(function(response){
this[value] = response.data[responseValue]
}.bind(this))
.catch(function(error){
console.log(error)
})
})
}

In case some will need multiple ajax request. Here is an example.
var app = new Vue({
el: '#app',
data: {
value: '',
admissions: [],
schoolyear: []
},
created: function(){
this.ajaxAll()
},
methods: {
ajaxAll: _.debounce( function(){
var app = this
var admissions = 'admissions'
var schoolYear = 'schoolyear'
axios.all([this.getAllData('http://localhost/school/api/admissions', 'admissions'), this.getAllData('http://localhost/school/api/schoolyear', 'schoolyear')]);
}),
getAllData: function(url, value){
var app = this
return axios.get(url)
.then(function(response){
app[value] = response.data[value]
console.log(response.data.admissions)
})
}
}
})
Credit to #Bert Evans.

Related

Async call for computed property - Vue.js

I have a computed property that will only be used if a match for a property exists. Because of this, I'm making the call to get the data asynchronous so that it's only retrieved when needed. I'm having an issue though trying to make an async call to return data for a computed property.
Below is what I have:
new Vue({
el: "#formCompleteContainer",
data: {
form: {},
components: []
},
computed: {
employeeList: function () {
var self = this;
if (_.some(this.components, function (component) {
return component.ComponentInfo.Type === 8
})) {
var employees = [];
$.ajax({
url: "/Form/GetAllUsers",
type: "GET"
}).done(function (results) {
employees = results;
});
return employees;
} else {
return [];
}
}
}
});
I know this isn't working because I'm returning before the call is complete. I've seen how to use deferredobjects and what not but I can't seem to figure out how to implement it with Vue.
For your use case, I don't think computed property can implement the goal.
My solution:
create one data property as one 'defered' object,
then uses one watch to async call your backend to get new data, finally assign to the defered object
like below demo:
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
product: "Boots",
deferedProduct: ''
},
watch: {
product: function (newVal, oldVal) {
setTimeout(() => {
this.deferedProduct = 'Cats in ' + newVal + '!'
}, 1500)
}
},
methods: {
nextProduct: function () {
this.product += 'a'
}
}
})
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<button #click="nextProduct()">Click Me!</button>
<h2>{{product}}</h2>
<h2>{{deferedProduct}}</h2>
</div>
This is what vue-async-computed is meant for. It resolves the promise you returned and handles any race conditions.
new Vue({
el: "#formCompleteContainer",
data: {
form: {},
components: []
},
asyncComputed: {
employeeList: function () {
if (_.some(this.components, function (component) {
return component.ComponentInfo.Type === 8
})) {
return $.ajax({
url: "/Form/GetAllUsers",
type: "GET"
});
} else {
return Promise.resolve([]);
}
}
}
});
After doing some more research I have gone another route. I agree with Sphinx that I don't think what I am trying to achieve will work with a computed property.
Instead, this is what I am going with:
new Vue({
el: "#formCompleteContainer",
data: {
form: {},
components: [],
employees: []
},
methods: {
getEmployees: function () {
var self = this;
if (_.some(this.components, function (component) {
return component.ComponentInfo.Type === 8;
})) {
$.ajax({
url: "/Form/Form/GetAllUsers",
type: "GET"
}).done(function (results) {
self.employees = results;
});
}
}
},
created: function () {
this.form = pageModel.Form;
this.components = pageModel.Components;
},
mounted: function () {
this.getEmployees();
}
});
As pointed out already, mounted and other 3rd party solutions can work.
However, better readability and component loading will come from putting the desired Promise within a data property. And then using the Vue lifecycle hook created, we can wait for that Promise to resolve with a .then.
For example:
requestService.js:
...
async foo(){
let myRequest = someRequest.createInstance()
await myRequest.onReady()
return myRequest.getSomePromise()
}
...
And then import the service into your component, as well as declaring a data prop:
myComponent.vue
...
data: (){
myPromiseLoc: null,
}
...
created: (){
requestService.foo().then( result =>
{
this.myPromiseLoc = result
}
}
...

Vue js: Is it posible to initialize data through a method?

Basically I want to initialize my vValidNombre field on my form by comparing two values, so It would be nice to use a method, something like this:
<script type="text/javascript">
var avatar = new Vue({
el: '#validaciones',
data: {
vNombre: $('input[name=nombre]').val(),
vValidNombre: validar(),
},
methods: {
validar: function(){
if ('true' == 'true') {
return = true;
}
else {
return false;
}
}
}
})
</script>
This code doesn't work, but is it possible to do something like that?
EDIT: I'm using Vue 2
Not really. When it is initialised, vValidNombre would be undefined. However, you can do something like this with the ready method:
var avatar = new Vue({
el: '#validaciones',
data: {
vNombre: $('input[name=nombre]').val(),
vValidNombre: null,
},
ready: function() {
this.vValidNombre = this.validar();
}
methods: {
validar: function(){
// do something here
// and return it
},
bindDom: function() {
}
},
})

vuejs set data value for v2.2.5

So here's my code
var portal = new Vue({
el: "#AnnounceController",
data: {
ann: {
id: '',
content: ''
},
announces: [],
success: false,
edit: false
},
methods: {
fetchAnnounce: function () {
axios.get('/api/announces')
.then(function (response) {
this.announces = response.data;
console.log(this.announces);
})
.catch(function (error) {
console.log(error);
});
}
},
computed: {},
mounted: function () {
console.log('mounted')
this.fetchAnnounce()
}
I have a GET request via axios to a laravel based api, when I look at the response from axios I do see my data, when I try to assign that data to the 'announces' from data, it doesn't work. Vue-devtools shows my data 'announces' attribute as empty, and the log for this.announces shows me my data, somehow like the data attribute for the vue instance and the this.announces are different.
fetchAnnounce: function () {
axios.get('/api/announces')
.then(function (response) {
this.announces = response.data;
console.log(this.announces);
}.bind(this))
.catch(function (error) {
console.log(error);
});
}

Angular 1.5.x/Jasmine - Expected spy to have been called but it was never called

POST-EDIT: I've just solved the issue, though maybe someone has a better solution. I'll post my solution soon, but if someone has a correct solution I'll accept their answer.
I'm migrating my application from 1.4 to 1.5 and changing all my controllers and directives to components. I now have a test that once worked not working and I'd like some guidance.
I'm trying to spy on a service method and according to the unit test it's not calling. This is not the case as an API call is made when the application is run. Here is the message I receive:
This is my component file:
(function(){
"use strict";
angular.module("app").component("profileComponent", {
templateUrl: "/templates/profile.component.html",
controllerAs: "vm",
bindings: {
resolvedUser: "<"
},
controller: function(ImageService, $state){
const vm = this;
const resolvedUser = this.resolvedUser;
resolvedUser ? vm.user = resolvedUser : $state.go("404");
vm.$onInit = function(){
ImageService.findByName(vm.user.pokemon.name)
.then(function(res){
vm.user.pokemon.id = res.id;
vm.user.pokemon.image = res.sprites.front_default;
vm.user.pokemon.type = res.types[0].type.name;
})
.catch(function(res){
vm.user.pokemon.image = "https://www.native-instruments.com/forum/data/avatars/m/328/328352.jpg?1439377390";
});
}
}
});
})();
And here is the relevant parts from my spec file. I've made a comment where the test is failing:
describe("profile.component", function(){
var profileComponent, ImageService, $q, $httpBackend, $state, resolvedUser, jazzSpy, IS,
API = "http://pokeapi.co/api/v2/pokemon/";
var RESPONSE_SUCCESS = // very large variable I've omitted for brevity.
beforeEach(angular.mock.module("app"));
beforeEach(angular.mock.module("ui.router"));
beforeEach(inject(function(_ImageService_, _$q_, _$httpBackend_, _$state_, _$rootScope_){
ImageService = _ImageService_;
$q = _$q_;
$httpBackend = _$httpBackend_;
$state = _$state_;
$rootScope = _$rootScope_;
$rootScope.$new();
}));
describe("profileComponent with a valid user and valid Pokemon", function(){
beforeEach(inject(function(_$componentController_){
singleUser = { id: 2, name: "Erlich Bachman", email: "erlich#aviato.com", phone: 4155552233, pokemon: { isPresent: true, name: "celebi"}, icon: { isPresent: false, name: null} };
let bindings = {resolvedUser: singleUser, ImageService: ImageService, $state: $state };
profileComponent = _$componentController_("profileComponent", { $scope: {} }, bindings);
profileComponent.$onInit();
}));
beforeEach(function(){
spyOn(ImageService, "findByName").and.callThrough();
});
it("should set state to resolvedUser", function(){
expect(profileComponent.user).toEqual(singleUser);
});
it("should expect ImageService to be defined", function(){
expect(ImageService.findByName).toBeDefined();
});
it("should call ImageService.findByName() and return Pokemon icon", function(){
expect(profileComponent.user.pokemon.name).toEqual("celebi");
$httpBackend.whenGET(API + "celebi").respond(200, $q.when(RESPONSE_SUCCESS));
$httpBackend.flush();
// This is where the test fails
expect(ImageService.findByName).toHaveBeenCalledWith("celebi");
});
});
As mentioned before, $onInit needs to be called after spyOn:
beforeEach(function(){
spyOn(ImageService, "findByName").and.callThrough();
profileComponent.$onInit();
});

VUEJS data.map is not a function

I am using VueJS and got an error message that I didnt have before. The incidents var is an array, so it should work I would assume?
In my HTML file I included:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.2.0/vue-resource.js"></script>
When I log the output of response.data I see an array:
Uncaught (in promise) TypeError: response.data.map is not a function
at Vue$3. (main.js:17)
var app = new Vue({
el: '#app',
data: {
responders: [],
incidents: []
},
mounted: function () {
this.getIncidents();
},
methods: {
getIncidents: function() {
console.log('getIncidents');
var app = this;
this.$http.get('/api/v1/incidents').then(function(response) {
// set data on vm
var incidentsReceived = response.data.map(function (incident) {
return incident
});
Vue.set(app, 'incidents', incidentsReceived);
});
}
})
You can not map over the response. Try setting the response data to your data so do
this.$http.get('/api/v1/incidents').then((response) => {
// set data in your data object
this.incidents = response.data
// Now you can map over the incidents and return
return this.incidents.map(incident => return)
});

Resources