Laravel 5.5 + Vue.js 2.x Proper API requests - javascript

I am working locally on a Laravel 5.5 project which uses Vue.js 2.5.9 on with XAMP Server.
I have to load some information to the DOM and refresh it when click "Refresh" button.
Sometimes the information is loaded and well displayed but sometimes they are not (some of the responses are):
Error 429: { "message": "Too Many Attempts." }
Error 500: { "message": "Server Error." }
I managed to "solve" the first issue (error 429) by increasing the Middleware throttle in Kernel.php from 'throttle:60,1', to 100,1)
But the second error I am not sure why I am get it sometimes and sometimes not.
I have this in my APIController (for example):
public function users()
{
$users = User::all();
return response()->json($users);
}
Then in app.js I call the methods in the created hook like this:
const app = new Vue({
el: '#app',
data: {
...
totalUsers: 0,
...
},
created: function() {
...
this.loadUsers();
...
},
methods: {
...
loadUsers: function() {
axios.get('/api/admin/users')
.then(function (response) {
app.totalUsers = response.data.length;
});
},
refreshData: function() {
this.loadUsers():
},
...
}
});
Maybe should I replace $users = User::all() to $users = User::count() to avoid loading "too much data" in API requests?

I think you should be using mounted() instead of created() in your vue.
const app = new Vue({
el: '#app',
data: {
...
totalUsers: 0,
...
},
mounted: function() {
...
this.loadUsers();
...
},
methods: {
...
loadUsers: function() {
axios.get('/api/admin/users')
.then(function (response) {
app.totalUsers = response.data.length;
});
},
refreshData: function() {
this.loadUsers():
},
...
}
});
that's the equivalent of the $(document).on(ready) in jQuery. Thats the method that fires when the window has fully loaded.
On a side note, Laravel knows when it is returning json as an ajax response, so you could probably just amend you controller method to this
public function users()
{
return User::all();
}

Related

Vue-cli project data update delays when sending request with Vuex and axios

I'm working on a project with Vue-CLI, and here's some parts of my code;
//vuex
const member = {
namespaced:true,
state:{
data:[]
},
actions:{
getAll:function(context,apiPath){
axios.post(`http://localhost:8080/api/yoshi/backend/${apiPath}`, {
action: "fetchall",
page: "member",
})
.then(function(response){
context.commit('displayAPI', response.data);
});
},
toggle:(context,args) => {
return axios
.post(`http://localhost:8080/api/yoshi/backend/${args.address}`,
{
action:"toggle",
ToDo:args.act,
MemberID:args.id
})
.then(()=>{
alert('success');
})
},
},
mutations:{
displayAPI(state, data){
state.tableData = data;
},
},
getters:{
getTableData(state){
return state.tableData
}
}
}
//refresh function in member_management.vue
methods: {
refresh:function(){
this.$store.dispatch('member/getAll',this.displayAPI);
this.AllDatas = this.$store.getters['member/getTableData'];
}
}
//toggle function in acc_toggler.vue
ToggleAcc: function (togg) {
let sure = confirm(` ${todo} ${this.MemberName}'s account ?`);
if (sure) {
this.$store
.dispatch("member/toggle", {
address: this.displayAPI,
id: this.MemberID,
act: togg,
Member: this.MemberName,
})
.then(() => {
this.$emit("refresh");
});
}
},
The acc_toggler.vue is a component of member_management.vue, what I'm trying to do is when ToggleAcc() is triggered, it emits refresh() and it requests the updated data.
The problem is , after the whole process, the data is updated (I checked the database) but the refresh() funciton returns the data that hadn't be updated, I need to refresh the page maybe a couple of times to get the updated data(refresh() runs everytime when created in member_management.vue)
Theoretically, the ToggleAcc function updates the data, the refresh() function gets the updated data, and I tested a couple of times to make sure the order of executions of the functions are right.
However, the situation never changes. Any help is appreciated!
The code ignores promise control flow. All promises that are supposed to be awited, should be chained. When used inside functions, promises should be returned for further chaining.
It is:
refresh:function(){
return this.$store.dispatch('member/getAll',this.displayAPI)
.then(() => {
this.AllDatas = this.$store.getters['member/getTableData'];
});
}
and
getAll:function(context,apiPath){
return axios.post(...)
...

Meteor Iron Router WaitOn Subscription

I am really struggling with waiting on a subscription to load for a specific route before returning the data to the template. I can see on from the publish on the server that a document is found, but on the client there is no document.
If I do a find().count() on the publish, it shows 1 document found, which is correct, but when I do the count on the subscription, it shows 0 documents.
I have tried a number of different methods, like using subscriptions:function() instead of waitOn:function(), but nothing works.
Collections.js lib:
SinglePackage = new Mongo.Collection("SinglePackage");
SinglePackage.allow({
insert: function(){
return true;
},
update: function(){
return true;
},
remove: function(){
return true;
}
});
Publications.js server:
Meteor.publish("SinglePackage", function(pack_id) {
return Packages.find({shortId: pack_id});
});
Iron Router:
Router.route('/package/:id', {
name: 'package.show',
template: 'Package_page',
layoutTemplate: 'Landing_layout',
waitOn: function() {
return Meteor.subscribe('SinglePackage', this.params.id);
},
data: function() {
return SinglePackage.find();
},
action: function () {
if (this.ready()) {
this.render();
} else {
this.render('Loading');
}
}
});
Am I doing something very wrong, or is this just a complicated thing to achieve? One would think that waitOn would make the rest of the function wait until the subscription is ready.
Any help would be highly appreciated.
It appears that the data function is running before the subscription is ready. Even if the data function did run after the subscription was ready, it wouldn't be a reactive data source rendering the pub/sub here pointless. Here's a great article on reactive data sources.
Referring to the example from the Iron Router Docs for subscriptions, you would do something like this:
Router.route('/package/:id', {
subscriptions: function() {
// returning a subscription handle or an array of subscription handles
// adds them to the wait list.
return Meteor.subscribe('SinglePackage', this.params.id);
},
action: function () {
if (this.ready()) {
this.render();
} else {
this.render('Loading');
}
}
});
Then in your template.js:
Template.Package_page.helpers({
singlePackage() {
// This is now a reactive data source and will automatically update whenever SinglePackage changes in Mongo.
return Package.find().fetch();
}
});
In your template.html you can now use singlePackage:
<template name="Package_page">
{#with singlePackage} <!-- Use #each if you're singlePackage is an array -->
ID: {_id}
{/with}
</template>

got property undefined when fetching data in ajax using vue.js

I have got a undefined when I alert the param fetching from ajax using vue.js, here is my code.
test.json return:
[
{isActive: false,name: test}
]
js:
new Vue({
el: '#viewport',
data: {
test_data: []
},
mounted: function () {
this.fetchTestData();
},
methods: {
fetchTestData: function () {
$.get(test.json, function (data) {
this.test_data = data;
alert(this.test_data.isActive);
});
}
}
});
I am beginner of vue.js, hope have a reply, thanks.
If you are fetching this data from that test.json file,
first it need to be like that because that's not validate json:
[
{
"isActive": false,
"name": "test"
}
]
and you need to use bind because this not referring to the Vue instance
fetchTestData: function () {
$.get('test.json', function (data) {
this.test_data = data;
alert(this.test_data[0].isActive);
}.bind(this));
}
and accessing the data like that this.test_data[0].isActive because it's an array

How to set a timer with a Vue.js class

im just using Vue.js to updates posts on a site im messing around with, this is what ive got so far (im still learning javascript, and not too great at it)
[app.js]
var Vue = require('vue');
Vue.use(require('vue-resource'));
var app = new Vue({
el: '#app',
components: {
'postlist' : require('./components/postlist/postlist.js')
}
});
[postlist.js]
module.exports = {
template: require('./postlist.template.html'),
data: function () {
return {
'search': '',
'posts' : {}
}
},
methods: {
'updatePosts' : function()
{
this.$http.get('api/posts', function(responce, status, request)
{
this.$set('posts', responce.data);
});
}
}
};
What I'm looking for is to have updatePosts fire off every x seconds, how do I do this?
ive tried doing this in the app.js
setInterval(function()
{
app.components.postlist.methods.updatePosts(); // doesnt work
app.postlist.updatePosts(); //doesnt work either
}, 500);
and tried putting the setInterval into the component itself
im pretty lost with this, whats the best way to achieve this?
updatePosts running every x seconds?
I have also trouble with scopes in Vue.
this should work
module.exports = {
template: require('./postlist.template.html'),
data: function () {
return {
'search': '',
posts: {}
}
},
methods: {
updatePosts: function () {
var self = this;
self.$http.get('api/posts', function(responce, status, request) {
self.posts = responce.data;
setTimeout(function(){ self.updatePosts() }, 2000);
});
}
},
created: function () {
this.updatePosts();
}
}
Functions in Vue works kinda different way, because your method updatePosts is not regular function. It is function defined in $vm.methods object. so It can't be called regularly like setTimeout($vm.updatePosts). Actually $vm.updatePosts doesn't exists. if you called it like $vm.updatePosts() it is different story. $vm instance automatically calls its method... So correct way is setTimeout(function(){ self.updatePosts() },2000)
You could start the request cycle in created or somewhere else in the lifecycle. It's also probably better to use recursion here so you can wait for the response to come back before you send off another one. I didn't test this code fully but it should work.
module.exports = {
template: require('./postlist.template.html'),
data: function () {
return {
'search': '',
posts: {}
}
},
methods: {
updatePosts: function () {
this.$http.get('api/posts', function(responce, status, request) {
this.posts = responce.data;
setTimeout(this.updatePosts, 2000);
});
}
},
created: function () {
this.updatePosts();
}
}

React/reflux how to do proper async calls

I recently started to learn ReactJS, but I'm getting confused for async calls.
Lets say I have a Login page with user/pass fields and login button. Component looks like:
var Login = React.createClass({
getInitialState: function() {
return {
isLoggedIn: AuthStore.isLoggedIn()
};
},
onLoginChange: function(loginState) {
this.setState({
isLoggedIn: loginState
});
},
componentWillMount: function() {
this.subscribe = AuthStore.listen(this.onLoginChange);
},
componentWillUnmount: function() {
this.subscribe();
},
login: function(event) {
event.preventDefault();
var username = React.findDOMNode(this.refs.email).value;
var password = React.findDOMNode(this.refs.password).value;
AuthService.login(username, password).error(function(error) {
console.log(error);
});
},
render: function() {
return (
<form role="form">
<input type="text" ref="email" className="form-control" id="username" placeholder="Username" />
<input type="password" className="form-control" id="password" ref="password" placeholder="Password" />
<button type="submit" className="btn btn-default" onClick={this.login}>Submit</button>
</form>
);
}
});
AuthService looks like:
module.exports = {
login: function(email, password) {
return JQuery.post('/api/auth/local/', {
email: email,
password: password
}).success(this.sync.bind(this));
},
sync: function(obj) {
this.syncUser(obj.token);
},
syncUser: function(jwt) {
return JQuery.ajax({
url: '/api/users/me',
type: "GET",
headers: {
Authorization: 'Bearer ' + jwt
},
dataType: "json"
}).success(function(data) {
AuthActions.syncUserData(data, jwt);
});
}
};
Actions:
var AuthActions = Reflux.createActions([
'loginSuccess',
'logoutSuccess',
'syncUserData'
]);
module.exports = AuthActions;
And store:
var AuthStore = Reflux.createStore({
listenables: [AuthActions],
init: function() {
this.user = null;
this.jwt = null;
},
onSyncUserData: function(user, jwt) {
console.log(user, jwt);
this.user = user;
this.jwt = jwt;
localStorage.setItem(TOKEN_KEY, jwt);
this.trigger(user);
},
isLoggedIn: function() {
return !!this.user;
},
getUser: function() {
return this.user;
},
getToken: function() {
return this.jwt;
}
});
So when I click the login button the flow is the following:
Component -> AuthService -> AuthActions -> AuthStore
I'm directly calling AuthService with AuthService.login.
My question is I'm I doing it right?
Should I use action preEmit and do:
var ProductAPI = require('./ProductAPI')
var ProductActions = Reflux.createActions({
'load',
'loadComplete',
'loadError'
})
ProductActions.load.preEmit = function () {
ProductAPI.load()
.then(ProductActions.loadComplete)
.catch(ProductActions.loadError)
}
The problem is the preEmit is that it makes the callback to component more complex. I would like to learn the right way and find where to place the backend calls with ReactJS/Reflux stack.
I am using Reflux as well and I use a different approach for async calls.
In vanilla Flux, the async calls are put in the actions.
But in Reflux, the async code works best in stores (at least in my humble opinion):
So, in your case in particular, I would create an Action called 'login' which will be triggered by the component and handled by a store which will start the login process. Once the handshaking ends, the store will set a new state in the component that lets it know the user is logged in. In the meantime (while this.state.currentUser == null, for example) the component may display a loading indicator.
For Reflux you should really take a look at https://github.com/spoike/refluxjs#asynchronous-actions.
The short version of what is described over there is:
Do not use the PreEmit hook
Do use asynchronous actions
var MyActions = Reflux.createActions({
"doThis" : { asyncResult: true },
"doThat" : { asyncResult: true }
});
This will not only create the 'makeRequest' action, but also the 'doThis.completed', 'doThat.completed', 'doThis.failed' and 'doThat.failed' actions.
(Optionally, but preferred) use promises to call the actions
MyActions.doThis.triggerPromise(myParam)
.then(function() {
// do something
...
// call the 'completed' child
MyActions.doThis.completed()
}.bind(this))
.catch(function(error) {
// call failed action child
MyActions.doThis.failed(error);
});
We recently rewrote all our actions and 'preEmit' hooks to this pattern and do like the results and resulting code.
I also found async with reflux kinda confusing. With raw flux from facebook, i would do something like this:
var ItemActions = {
createItem: function (data) {
$.post("/projects/" + data.project_id + "/items.json", { item: { title: data.title, project_id: data.project_id } }).done(function (itemResData) {
AppDispatcher.handleViewAction({
actionType: ItemConstants.ITEM_CREATE,
item: itemResData
});
}).fail(function (jqXHR) {
AppDispatcher.handleViewAction({
actionType: ItemConstants.ITEM_CREATE_FAIL,
errors: jqXHR.responseJSON.errors
});
});
}
};
So the action does the ajax request, and invokes the dispatcher when done. I wasn't big on the preEmit pattern either, so i would just use the handler on the store instead:
var Actions = Reflux.createActions([
"fetchData"
]);
var Store = Reflux.createStore({
listenables: [Actions],
init() {
this.listenTo(Actions.fetchData, this.fetchData);
},
fetchData() {
$.get("http://api.com/thedata.json")
.done((data) => {
// do stuff
});
}
});
I'm not big on doing it from the store, but given how reflux abstracts the actions away, and will consistently fire the listenTo callback, i'm fine with it. A bit easier to reason how i also set call back data into the store. Still keeps it unidirectional.

Categories

Resources