I'm using laravel with vue I'd like to update my data in real-time (when new post/project) is published the main page add it (no refresh required)
Question
How can I do that?
code
my component
<div v-for="project in projects" :key="project.slug">
my script
<script>
import pagination from 'laravel-vue-pagination';
var moment = require('moment');
export default {
data() {
return {
projects: {},
app_name: process.env.MIX_APP_NAME,
}
},
mounted: function() {
this.load();
},
components: {
pagination
},
methods: {
//shorting projects body
readMore: function (text, length, suffix) {
return text.substring(0, length) + suffix;
},
//getting all projects
load: function(page = 1) {
Vue.use(require('vue-moment'), {
moment
});
axios.get('/api/projects?page=' + page)
.then(
response => {
this.projects = response.data.data;
// timing
Vue.filter('timeAgo', function(value){
return moment(value).fromNow();
});
//adding tooltip
Vue.nextTick(function () {
$('[data-toggle="tooltip"]').tooltip();
});
}
)
.catch(function (error) {
this.errors.push(error);
console.log(error);
})
},
//numbers decimals
formatPrice(value) {
let val = (value/1).toFixed(0).replace('.', ',')
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")
},
}
}
</script>
sorry for part below (is just to be able to post this question
stackoverflow limitations
.......................................................................................................................................................................................................................................
You'll need to look into Websockets if you want the server to able to update the client of when there is new data.
The flow would be: new item added, Websocket from server sends this new item as json to all clients, client adds this item to the javascript list of items, vue auto updates the visible list to reflect this new item.
If websockets are impossible then you'll need to just run your load command on a short timer so it feels "real-time ish"
Related
I have a todo app (react-native) with graphql-client connect
const client = new ApolloClient({
uri: API,
cache: new InMemoryCache()
});
when I add a new todo or delete, I need to update the cache so the changes could show without refreshing
createTodo({
variables: { text: todo },
update(proxy, result) {
const data = proxy.readQuery({
query: FETCH_TODOS
});
data.getTodos = [result.data.createTodo, ...data.getTodos];
proxy.writeQuery({
query: FETCH_TODOS,
data
});
}
});
}
the problem is, I had to call the writeQuery inside the item's component. and if I invoked it in the form component. Nothing happened. why?
update
this code worked just fine, but the createTodo did not.
const hanglePress = key => {
deleteTodo({
variables: { todoId: key },
update(proxy) {
const data = proxy.readQuery({
query: FETCH_TODOS
});
data.getTodos = data.getTodos.filter(todo => todo.id !== key);
proxy.writeQuery({ query: FETCH_TODOS, data });
}
});
};
I am trying to integrate google-recaptcha but no success.
Getting error
feedback.js:39 Uncaught TypeError: grecaptcha.render is not a function
main.js
'googlerecaptcha':'https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit',
define(['ojs/ojcore', 'knockout', 'jquery', 'appController', 'ckeditor', 'googlerecaptcha', 'ojs/ojlabel',
'ojs/ojknockout', 'ojs/ojinputtext', 'ojs/ojformlayout'],
function (oj, ko, $, app, ckeditor, grecaptcha) {
/**
* The view model for the main content view template
*/
function feedbackViewModel() {
var self = this;
// For small screens: labels on top
// For medium screens and up: labels inline
this.labelEdge = ko.computed(function () {
return app.smScreen ? "top" : "start";
}, this);
onloadCallback = function (a) {
grecaptcha.render('submit', {
'sitekey': 'YOUR_API_KEY',
'callback': self.onSubmit
}, true);
};
this.handleActivated = function (info) {
};
self.onSubmit = function (token) {
console.info("google recatpcha onSubmit", token)
//do validation/application code using token
var data = {secret: grecaptcha, response: recaptchaToken};
$.post({
url: "https://www.google.com/recaptcha/api/siteverify",
form: data
}).then(function (e) {
//recaptcha service called...check result
var resp = JSON.parse(e);
if (resp.success == false) {
console.info("recaptcha token outcome is false")
} else {
console.info("recaptcha token validated")
}
});
};
}
return feedbackViewModel;
});
Do you have a mapping for 'googlerecaptcha' in src/js/path_mapping.json? If I go to https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit, I do not see that it is returning any valid object. So most likely 'grecaptcha' variable is undefined.
reCaptcha + RequireJS
Looks like reCaptcha is a function that has to be executed vs an object that can be interacted with directly. So you may need a different approach, something mentioned in this thread.
Im using vue js to update a few things on my page, its real simple use case
Vue.component('my-component', {
template: '.....<a v-on:click="myfunction">data</a>{{stuff}}'
data: {
stuff: 0
}
mounted(){
let __this = this;
axios.....then(function (data){ __this.stuff = 1l }); // works
}
methods: {
myfunction: function(){
this.stuff = 2; /// dosnt work. template not rendered
}
}
});
Any particular way to set the variable to detect changes or any pointers ? thanks.
For reusable components, your data field should actually be a function that returns the data object:
Vue.component('my-component', {
template: '.....<a v-on:click="myfunction">data</a>{{stuff}}',
data() {
return {
stuff: 0
};
},
mounted(){
let __this = this;
axios.....then(function (data){ __this.stuff = 1l }); // works
},
methods: {
myfunction: function(){
this.stuff = 2; // should work now
}
}
});
Please review the relevant section of the Vue.js documentation for more information concerning this issue.
I have a react component - coursePage.js
function getCourseInitState(){
return {
courses: CourseStore.getAllCourses()//courseStore is required in script
};
}
var Courses = React.createClass({
getInitialState: function(){
return getCourseInitState();
},
render: function () {
return (
<div>
<h1> Course </h1>
<CourseList courses={this.state.courses} />
</div>
);
}
});
Action file -courseAction
var CourseAction = {
CourseList: function(){
var courseList = CourseApi.getAllCourses();
Dispatcher.dispatch({
actionType: ActionTypes.COURSE_INITIALIZE,
courseList: courseList
});
}
Store File - courseStore
var CourseStore = assign({}, EventEmitter.prototype, {
addChangeListener: function(callback){
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback){
this.removeListener(CHANGE_EVENT, callback);
},
emitChange: function(){
this.emit(CHANGE_EVENT);
},
getAllcourses: function(){ //here is the function define
return _courses;
},
getCourseById: function(id){
return _.find(_courses, {id: id});
}
});
Dispatcher.register(function(action){
switch(action.actionType){
case ActionTypes.COURSE_INITIALIZE:
_courses = action.CourseList;
CourseStore.emitChange();
break;
}
});
module.exports = CourseStore;
in console I am getting "Uncaught TypeError: CourseStore.getAllCourses is not a function"
I don't want to call api directly in my coursePage.js so I find this way of initialising the page but it is not working.
(Please note - I am new to this) As per my recent learning Action file must always call API and send the request to State. I can load with help of componentWillMount function. But, I wanted to solve with this.If not wrong, then it is more neat and preferable way of implementing?
You have a typo -> getAllcourses in the Store and in the Component you call getAllCourses
getAllCourses: function(){ //Should be getAllCourses instead of getAllcourses
return _courses;
},
I'm using Bootstrap Typeahead to suggest som search results. The results are returned from a ajax ressource, and since this resource creates a delay, I'm experiencing a unfortunate effect.
Example:
If typing a 4 letter word, the suggestions will appear after 2 letters, I can then go through the results with the keys up/down, but suddenly the suggestions will reload because the last request has finished.
Is there any way to "cancel" any remaining, if user is currently using the keys up/down to go through the suggestions?
('#query').typeahead({
items: 4,
source: function (query,process) {
map = {};
$.getJSON('/app_dev.php/ajax/autosuggest/'+query, function (data) {
vehicles = [];
$.each(data, function(i,vehicle){
map[vehicle.full] = vehicle;
vehicles.push(vehicle.full);
});
process(vehicles);
});
},
updater: function (item) {
// do something here when item is selected
},
highlighter: function (item) {
return item;
},
matcher: function (item) {
return true;
}
});
I think the following will satisfy your needs (its hard to reproduce exactly) :
There is no easy way to abort a delayed response, but you could extend typeahead as I figured out here (without modifying bootstrap.js)
The concept is to catch keydown, detect if the event is KEY_UP or KEY_DOWN, set a flag is_browsing, and then abort process if is_browsing is true (that is, if the user has hitted KEY_UP or KEY_DOWN and no other keys afterwards).
Extending typeahead :
// save the original function object
var _superTypeahead = $.fn.typeahead;
// add is_browsing as a new flag
$.extend( _superTypeahead.defaults, {
is_browsing: false
});
// create a new constructor
var Typeahead = function(element, options) {
_superTypeahead.Constructor.apply( this, arguments )
}
// extend prototype and add a _super function
Typeahead.prototype = $.extend({}, _superTypeahead.Constructor.prototype, {
constructor: Typeahead
, _super: function() {
var args = $.makeArray(arguments)
// call bootstrap core
_superTypeahead.Constructor.prototype[args.shift()].apply(this, args)
}
//override typeahead original keydown
, keydown: function (e) {
this._super('keydown', e)
this.options.is_browsing = ($.inArray(e.keyCode, [40,38])>-1)
}
//override process, abort if user is browsing
, process: function (items) {
if (this.options.is_browsing) return
this._super('process', items)
}
});
// override the old initialization with the new constructor
$.fn.typeahead = $.extend(function(option) {
var args = $.makeArray(arguments),
option = args.shift()
// this is executed everytime element.modal() is called
return this.each(function() {
var $this = $(this)
var data = $this.data('typeahead'),
options = $.extend({}, _superTypeahead.defaults, $this.data(), typeof option == 'object' && option)
if (!data) {
$this.data('typeahead', (data = new Typeahead(this, options)))
}
if (typeof option == 'string') {
data[option].apply( data, args )
}
});
}, $.fn.typeahead);
This typeahead-extension could be placed anywhere, eg in a <script type="text/javascript"> -section
Testing the extension :
<input type="text" id="test" name="test" placeholder="type some text" data-provide="typeahead">
<script type="text/javascript">
$(document).ready(function() {
var url='typeahead.php';
$("#test").typeahead({
items : 10,
source: function (query, process) {
return $.get(url, { query: query }, function (data) {
return process(data.options);
});
}
});
});
</script>
A "serverside" PHP script that returns a lot of randomized options with forced delay, typeahead.php :
<?
header('Content-type: application/json');
$JSON='';
sleep(3); //delay execution in 3 secs
for ($count=0;$count<30000;$count++) {
if ($JSON!='') $JSON.=',';
//create random strings
$s=str_shuffle("abcdefghijklmnopq");
$JSON.='"'.$s.'"';
}
$JSON='{ "options": ['.$JSON.'] }';
echo $JSON;
?>
It really seems to work for me. But I cannot be sure that it will work in your case. Let me now if you have success or not.