Updating vuejs component with ajax call from the parent - ajax

New to VueJs. I'm wondering how/where would I make an Ajax call to pull data dynamically down to populate the following Vue table?
https://jsfiddle.net/yyx990803/xkkbfL3L/?utm_source=website&utm_medium=embed&utm_campaign=xkkbfL3L
I've (roughly) modified the example above as follows:
var demo = new Vue({
el: '#demo',
data: {
searchQuery: '',
gridColumns: ['name', 'power'],
gridData: []
},
methods: {
fetchUsers: function() {
...
// ajax call using axiom, fetches data into gridData like this:
axios.get('http://localhost/url')
.then(function(response) {
this.gridData = response.data;
})
.catch(function(error) { console.log("error"); })
...
}
},
created: function() {
this.fetchUsers();
}
})
I'm trying to incorporate the ajax pieces from here:
https://jsfiddle.net/chrisvfritz/aomd3y9n/
I've added the fetchUser method which makes the ajax call to pull the data down. I'm able to pull down my data and print it to the console using both fetch and axiom, so I know that part works.
However, my data never appears or updates. The table loads blank. I think it has something to do with me putting the method and created hook on the Vue model object (demo), rather than on the component itself. But I'm not quite sure how to modify the example to resolve it, as the example passes the data in from the parent.
Can someone give me some guidance?

You problem is right over here:
.then(function(response) {
this.gridData = response.data;
})
Within your anonymous function within your then you don't have the context you expect. The most simple solution is adding a .bind(this) to the method.
.then(function(response) {
this.gridData = response.data;
}.bind(this))
By adding it your method body will be aware of the outer context and you can access your components data.

Related

Pass DataTable reference to the callback function on load

My current code is:
var CommissionLogs = $("#CommissionLogs").DataTable({
ajax: {
url: ajaxurl + '?action=pos&post_action=get_commissions'
},
'initComplete': function (settings, json){
//possible to access 'this'
this.api().columns(1);
}
});
I improved the code above as below with help :
var CommissionLogs = $("#CommissionLogs").DataTable({
ajax: {
url: ajaxurl + '?action=pos&post_action=get_commissions'
},
'initComplete': function(settings, json){
callbackFunction(settings);
}
});
function callbackFunction(settings){
var api = new $.fn.dataTable.Api( settings );
// api is accessible here.
}
Update :
Now I can access api from callback function. But I want use same callback with load() as below code.
CommissionLogs.ajax.url( newAjaxURL ).load( callbackFunction(), true);
But settings param is not accessible in load function.
I can clear and destroy datatable and re initialize always. But what will be the right way.
I think you need settings:
https://datatables.net/reference/type/DataTables.Settings
$('#example').dataTable( {
"initComplete": function(settings, json) {
myFunction(settings);
}
});
function myFunction(settings){
var api = new $.fn.dataTable.Api( settings );
// Output the data for the visible rows to the browser's console
// You might do something more useful with it!
console.log( api.rows( {page:'current'} ).data() );
}
Other option is re-use your var CommissionLogs variable throughout the code without using this, I recommend strongly this last option.
The dataTable.ajax.url().load() has not access to settings.
So can not call a callback function with settings.
But possible to use callback function without settings.
So here is an alternative way to use settings.
CommissionLogs.clear();// clear the table
CommissionLogs.destroy();// destroy the table
CommissionLogs = $("#CommissionLogs").DataTable({
ajax: {
url: newAjaxUrl
},
'initComplete': function (settings, json){
callbackDatatableFunciton(settings);
}
});

When i set axios response in vue js i get an empty array in laravel blade

I am trying to display results in my page, When i log response. I can see the response, I have tried passing the response to vue js data, but each time it displays an empty array
var app = new Vue({
el: '#app',
data: {
results: []
},
mounted(){
var url = "{{ url('fetch/messages') }}";
axios.get(url)
.then(function (response) {
console.log(response.data);
this.results = response.data;
})
.catch(function (error) {
console.log(error);
});
}
I am trying to display the response in the page #{{ results }}
The reason your data is not getting added to the Vue instance is because this will not refer to the Vue instance inside a closure (traditional function () {}). Please have a look at this article for more information on scope and this keyword in javascript.
Below I refer to ES quite a bit which stands for ECMAScript. Here is an article to show the difference between it and vanilla javascript.
I can see from your post that you're using ES6/ES2015 syntax for your method definitions so I'm assuming you're happy with just using modern browsers for now.
If this is the case then you can use Arrow Functions to get past the scope issue:
.then(response => {
console.log(response.data);
this.results = response.data;
})
If not, then as mentioned in the scope article above, you would need to assign this to a variable:
var self = this;
axios.get(url)
.then(function (response) {
console.log(response.data);
self.results = response.data;
});
If this is the case, then I would also suggest not using the ES6 method definitions either so change mounted(){ to mounted: function () {.
Finally, if you want to be able to use modern/new javascript e.g. ES6/ES2015 and above, but have your code work consistently with older browsers then I would suggest using something like Laravel mix to compile your javascript for you.
Laravel Mix Documentation
Laravel Mix tutorial series
You cannot have the following line of code, it will break.
var url = "{{ url('fetch/messages') }}";

How to ajax call from RiotControl Store?

I have created APIs with Nodejs/Express.
Let say I can do GET request to localhost:8080/list and it returns JSON of my TODO list and I can POST to localhost:8080/list to create new to do list.
Then I use Riotjs + Riotcontrol for my Frontend website.
How do I request from todostore.js file?
This is the riotcontrol todostore.js file which I get from riotcontrol demo folder
Riotcontrol
// TodoStore definition.
// Flux stores house application logic and state that relate to a specific domain.
// In this case, a list of todo items.
function TodoStore() {
riot.observable(this) // Riot provides our event emitter.
var self = this
self.todos = [
{ title: 'Task 1', done: false },
{ title: 'Task 2', done: false }
]
// Our store's event handlers / API.
// This is where we would use AJAX calls to interface with the server.
// Any number of views can emit actions/events without knowing the specifics of the back-end.
// This store can easily be swapped for another, while the view components remain untouched.
self.on('todo_add', function(newTodo) {
self.todos.push(newTodo)
self.trigger('todos_changed', self.todos)
})
self.on('todo_remove', function() {
self.todos.pop()
self.trigger('todos_changed', self.todos)
})
self.on('todo_init', function() {
self.trigger('todos_changed', self.todos)
})
// The store emits change events to any listening views, so that they may react and redraw themselves.
}
You could do something like this in your TodoStore
self.on('todo_init', function() {
// Trigger loading here perhaps, then set loading = false when it's loaded
//self.trigger('set_loading', {value: true})
fetch('http://localhost:8080/list')
.then(response => response.json())
.then(function (json) {
self.todos = json
self.trigger('todos_changed', self.todos)
})
})

How to deal with async requests in Marionette?

I am trying to fill in an ItemView in Marionette with the combined results of 2 API requests.
this.standings = App.request('collection:currentStandings');
this.userInfo = App.request('model:userInfo');
this.standings.each(function(s) {
if (s.currentUser) {
s.set('alias', this.userInfo.alias);
s.set('imageURL', this.userInfo.imageURL);
}
});
userInfoView = new LeagueBar.UserInfo({ collection: this.standings });
The problem is, the combination never happens because the requests have not been fulfilled before I try to combine them.
I know I probably need to add a promise for each request, but I haven't been able to find a clean way to do it. I could make 'collection:currentStandings' and 'model:userInfo' return promises, however, they are currently used in many other parts of the code, so I would have to go back and add .then()s and .done()s all over the code base where they weren't required before.
Any ideas or suggestions?
EDIT:
I have currently solved this in a less-than-ideal way: I created a template/view for the alias and a template/view for the imageURL and kept the template/view for the standings info. This doesn't seem like the best way and I'm interested to know the right way to solve this problem.
here are the two requests I am trying to combine:
Models.CurrentStandings = App.Collection.extend({
model: Models.PlayerStandings,
url: function() { return 'leagues/' + App.state.currentLeague + '/standings'; },
parse: function(standings) {
return _.map(standings, function(s) {
if (s.memberId == App.user.id)
s.currentUser = true;
return s;
});
}
});
App.reqres.setHandler('collection:currentStandings', function() {
weekStandings = new Models.CurrentStandings();
weekStandings.fetch({ success: function(data){ console.log(data); }});
return weekStandings;
});
Models.UserInfo = App.Model.extend({
url: 'users/me'
});
App.reqres.setHandler('model:userInfo', function(options) {
myuser = new Models.UserInfo();
myuser.fetch(options);
return myuser;
});
There are 2 solutions which based on your dependencies among views can be selected:
You can create views which are handling 'change' event of Models.UserInfo and when the data is ready (Change/Reset event raised) re-render the content. It is probably your solution.
If you are looking for a solution which should not create instance of LeageBar.UserInfo until both Models.CurrentStanding and Models.UserInfo are ready, you have to return the result of fetch function, so you may remove calling fetch from setHandlers and use them as following:
this.standings = App.request('collection:currentStandings');
this.userInfo = App.request('model:userInfo');
var that=this;
that.standings.fetch().done(function(){
that.userInfo.fetch().done(function(){
that.standings.each(function(s) {
if (s.currentUser) {
//....
}
});
userInfoView = new LeagueBar.UserInfo({ collection: that.standings });
});

Deferred Promises with AJAX in Angular

I'm trying to send data to my view from an AJAX call to my API. I am able to successfully hit my API and get data, but I was having problems with the view rendering before the AJAX call came back.
I'm trying to wrap my AJAX call in a Promise but it's not working. Here's my layout
Controller
.controller('DashCtrl', function($scope, Tweets) {
$scope.tweets = Tweets.all()
})
Factory doing ajax call
.factory('Tweets', function($http) {
$http.get('http://localhost:3000/tweets')
.success(function(data) {
var tweets = data
debugger
})
return {
all: function() {
//should return the results of the AJAX call when it's complete
}
}
});
I've tried making wrapping the ajax call into a function and using .then(function(payload){ return payload.data }) - Payload.data has my data but its never returned when I call the function. I'm new to angular, so I would appreciate any help or insight.
You should define your factory as
.factory('Tweets', function($http) {
return {
all: function() {
return $http.get('http://localhost:3000/tweets')
.then(function(response) {
return reponse.data;
})
}
}
});
Then change your controller to
.controller('DashCtrl', function($scope, Tweets) {
Tweets.all().then(function(data) {
$scope.tweets = data;
});
})
Use the $resource service. The docs don't mention it, but comments in the source do.
$resolved: true after first server interaction is completed (either with success or rejection), false before that.
So in the controller:
$scope.tweets = $resource('/tweets').query()
And in the view:
<div ng-if="tweets.$resolved">
Loading data with ngResource or from factory promise callback are viable options, but there's one more way nobody mentioned yet: resolve data to controller via route definition. This approach allows to write simplistic controllers that don't know how to load data at all. In most cases it will be more than enough if you don't need to load data dynamically, like pagination or infinite scroll.
You will need to define route and resolve function:
angular
.module('app', ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'ctrl',
controllerAs: 'view',
templateUrl: 'view.html',
resolve: {
tweets: function (Tweets) {
return Tweets.all();
}
}
})
})
The tweets property on resolve will inject loaded data into controller as tweets, all you have to do is just assign received data:
.controller('ctrl', function (tweets) {
this.tweets = tweets;
});
In addition, here's how Tweets service might look like:
.factory('Tweets', function ($timeout) {
function all () {
return $timeout(function () {
return ["hey", "there"];
});
}
return {
all: all
};
})
Basically, it exposes methods that return promise, returning some data ($timeout returns promise too, so I've used it instead of $http for example purpose).
Full example on JS Bin.

Resources