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();
}
}
Related
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();
}
document.addEventListener("DOMContentLoaded", function(event) {
var app = new Vue({
el: '#app',
data: {
posts: {}
},
mounted: function() {
},
methods: {
updatePosts: function () {
$.get('/api/v1/posts',function(response){
this.posts = response.data;
setInterval(this.updatePosts, 10000);
}.bind(this));
};
},
created: function () {
this.updatePosts();
}
});
});
I'm making an api call and want to run the updatepost method every 10 seconds. Currently, it runs except the 10 second timer gets reset on every page reload. How would I run this function every 10 seconds but not when the page gets refreshed?
I'm not sure if I understand your problem correctly, you want to stop the updatePosts call if the page refreshes, maybe you could use a route param to allow the created event to trigger updatePosts only if said param exists.
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>
I'm trying to build a simple app in vue and I'm getting an error. My onScroll function behaves as expected, but my sayHello function returns an error when I click my button component
Property or method "sayHello" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option. (found in component )
Vue.component('test-item', {
template: '<div><button v-on:click="sayHello()">Hello</button></div>'
});
var app = new Vue({
el: '#app',
data: {
header: {
brightness: 100
}
},
methods: {
sayHello: function() {
console.log('Hello');
},
onScroll: function () {
this.header.brightness = (100 - this.$el.scrollTop / 8);
}
}
});
I feel like the answer is really obvious but I've tried searching and haven't come up with anything. Any help would be appreciated.
Thanks.
But for a few specific circumstances (mainly props) each component is completely isolated from each other. Separate data, variables, functions, etc. This includes their methods.
Thus, test-item has no sayHello method.
You can get rid of the warning by using .mount('#app') after the Vue instance rather than the el attribute.
Check the snippet below;
var app = new Vue({
data: {
header: {
brightness: 100
}
},
methods: {
sayHello: function() {
console.log('Hello');
},
onScroll: function () {
this.header.brightness = (100 - this.$el.scrollTop / 8);
}
}
}).mount('#app');
Please note; the following might not be necessary but did it along the way trying to solve the same issue: Laravel Elixir Vue 2 project.
I have a dojo object, I want to do a retry connection to a web socket. However, the connection to the web socket is triggered by a callback function. I tried subscribing to a topic to allow reconnect without using this. However, if the class has two or more instance, it gets all the subscribed message on all instance of MyClass. Is there a way to only let the original instance that fail to connect to get the subscribed message?
// Dojo class
dojo.declare("MyClass", null, {
constructor: function() {
dojo.subscribe("WebSocketConnect", this, function() {
this.DoConnect();
});
},
DoConnect: function() {
this.myWebSocket = new WebSocket('ws://192.0.0.1');
// ウェブソケットは閉じたイベント
this.myWebSocket.onclose = function () {
// The this in this clousure is "myWebSocket"
setTimeout(function() {
dojo.publish("WebSocketConnect", [ ] );
}, 5000);
};
}
}
Note: The project I am working on uses dojo 1.4. Quite old but I have no permission to upgrade it.
Any particular reason you dont want to connect to this?
When you publish or subscribe, it is dependent on the string id used to identify the "event", If you could make it unique for each instance then you could prevent the function execute on all instance.
// Dojo class
dojo.declare("MyClass", null, {
uniqueID:"",
constructor: function() {
this.uniqueID = <generate unique id>;
dojo.subscribe("WebSocketConnect" + this.uniqueID, this, function() {
this.DoConnect();
});
},
DoConnect: function() {
var self = this;
this.myWebSocket = new WebSocket('ws://192.0.0.1');
// ウェブソケットは閉じたイベント
this.myWebSocket.onclose = function () {
// The this in this clousure is "myWebSocket"
setTimeout(function() {
dojo.publish("WebSocketConnect" + self.uniqueID, [ ] );
}, 5000);
};
}
}
How you generate the uniqueID is upto you, it could be as simple as a global counter or use some logic to create a GUID. Anything will work as long as it is unique.
Use a dynamic topic name:
// Dojo class
define(['dijit/registry', 'dojo/_base/declare', 'dojo/topic'], function(registry, declare, topic) {
declare("MyClass", null, {
constructor: function() {
var uniqId = registry.getUniqueId('WebSocketConnect'),
doConnect = this._DoConnect;
//for external use
this.DoConnect = function() {
doConnect(uniqId);
}
//from internal fail
topic.subscribe("WebSocketConnect" + uniqId, this.DoConnect());
},
_DoConnect: function(uniqId) {
this.myWebSocket = new WebSocket('ws://192.0.0.1');
// ウェブソケットは閉じたイベント
this.myWebSocket.onclose = function() {
// The this in this clousure is "myWebSocket"
setTimeout(function() {
topic.publish("WebSocketConnect" + uniqId, []);
}, 5000);
};
}
}
});
});
but best is to use hitch:
// Dojo class
define(['dojo/_base/declare'], function(declare) {
declare("MyClass", null, {
DoConnect: function() {
this.myWebSocket = new WebSocket('ws://192.0.0.1');
// ウェブソケットは閉じたイベント
this.myWebSocket.onclose = lang.hitch(this, function() {
setTimeout(lang.hitch(this, 'DoConnect'), 5000);
});
}
}
});
});