How to add loader in vue js - laravel

How to add Loading effect in VUE js plus Laravel.
This is a single page website in vuejs, i want to add loader when i change the route.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Means when i click to another router, it takes time to fetch data and show meanwhile i want to show loader. Or When i submit a form i takes time for submit meanwhile i want to add loader.
Help please in VUE js + Laravel

add this line of code in your app.js file
router.beforeEach((to, from, next) => {
// add loader
next()
})
router.afterEach(() => {
// terminate you loader
})
so Full file is
window.Vue = require('vue');
import VueRouter from 'vue-router';
import VueProgressBar from 'vue-progressbar'
window.Fire = new Vue();
Vue.use(VueProgressBar, {
color: 'rgb(143, 255, 199)', //normal color for progress bar
failedColor: 'red', //color for failed progress bar
height: '2px'//height of progress bar can be changed here
})
Vue.component(HasError.name, HasError)
Vue.component(AlertError.name, AlertError)
Vue.use(VueRouter);
window.Fire = new Vue();
let routes = [
{
path: '/',
name: 'posts',
component: post,
},
{
path: '/general',
name: 'dashboard',
component: Dashboard,
},
];
let router = new VueRouter({
routes // short for `routes: routes`
});
router.beforeEach((to, from, next) => {
// add loader
VueProgressBar .start();
next()
})
router.afterEach(() => {
// terminate you loader
VueProgressBar.finish();
})
const app = new Vue({
el: '#app',
router,
data: {},
methods: {}
});
window.Fire = new Vue();

If you are requesting while browsing through the pages, the loader can work accordingly.
<script>
export default {
data: () => ({
loaderIsActive: false,
items: null,
}),
mounted() {
this.fetch();
},
methods: {
async fetch() {
this.loaderIsActive = true;
this.items = await axios.post('YOUR API');
this.loaderIsActive = false;
}
}
}
In this way you can use it.

Related

NativeScript vue, vuex and urlhandler

Edit
I'm using https://github.com/hypery2k/nativescript-urlhandler to open a deep link within my app - using NativeScript vue, and vuex. It seems that in order to get at the methods needed to do routing [$navigateTo etc] this plugin needs to be set up slightly differently from the examples given in docs.
import Vue from "nativescript-vue";
import Vuex from "vuex";
Vue.use(Vuex);
import { handleOpenURL } from 'nativescript-urlhandler';
new Vue({
mounted() {
handleOpenURL( (appURL) => {
console.log(appURL)
// Settings is the variable that equals the component - in this case settings.
this.$navigateTo(Settings);
});
},
render: h => h("frame", [h(Home)]),
store: ccStore
}).$start();
handleOpenURL needs to be called within Mounted - then you can parse out the appURL and reference the page (component) that you wish to navigate to. I have been advised against calling handleOpenURL from within router - but I'm not sure why, and it works without error - and I have access to the methods for routing... so if anyone knows if this is a bad idea - please let me know :) Thanks!
All the stuff below that I wrote before has probably confused things - I'm referencing components within my vuex store to make them easily available from the router.
This is based on a solution by https://github.com/Spacarar - it can be found here: https://github.com/geodav-tech/vue-nativescript-router-example. It's a great solution because you don't have to include every single component within each component to use in navigation - it gives an almost vue router like experience.
I'm using https://github.com/hypery2k/nativescript-urlhandler to open a deep link within my app - however, I'm having problems opening the link.
In my app.js file, I have the following:
import Vue from "nativescript-vue";
import Vuex from "vuex";
Vue.use(Vuex);
....
import { handleOpenURL } from 'nativescript-urlhandler';
import ccStore from './store/store';
handleOpenURL(function(appURL) {
// I have hardwired 'Settings' in for testing purposes - but this would be the appURL
ccStore.dispatch('openAppURL', 'Settings');
});
....
new Vue({
render: h => h("frame", [h(Home)]),
store: ccStore
}).$start();
I'm storing the route state within vuex, and have various methods which work (clicking on a link loads the component). However, handleOpenURL exists outside of vue... so I've had to access vuex directly from within the handleOpenURL method. I've created an action specifically for this case - openAppURL.. it does exactly the same thing as my other methods (although I've consolidated it).
When clicking on an app link, I am NOT taken to the page within the app. I have put a console log within openAppURL and can see it is being called, and the correct route object is returned... it just doesn't open the page. The SetTimeOut is used because nextTick isn't available from within vuex.
I am at a loss on how to get the page to appear...
const ccStore = new Vuex.Store({
state: {
user: {
authToken: null,
refreshToken: null,
},
routes: [
{
name: "Home",
component: Home
},
{
name: "Log In",
component: Login
},
...
],
currentRoute: {
//INITIALIZE THIS WITH YOUR HOME PAGE
name: "Home",
component: Home //COMPONENT
},
history: [],
},
mutations: {
navigateTo(state, newRoute, options) {
state.history.push({
route: newRoute,
options
});
},
},
actions: {
openAppURL({state, commit}, routeName ) {
const URL = state.routes[state.routes.map( (route) => {
return route.name;
}).indexOf(routeName)];
return setTimeout(() => {
commit('navigateTo', URL, { animated: false, clearHistory: true });
}, 10000);
},
....
}
etc....
I have been advised to post my findings as the answer and mark it as correct. In order to use nativescript-urlhandler with vue, you must initialise the handler from within vue's mounted life cycle hook. Please see above for greater detail.
import Vue from "nativescript-vue";
import Vuex from "vuex";
Vue.use(Vuex);
import Settings from "~/components/Settings";
import { handleOpenURL } from 'nativescript-urlhandler';
new Vue({
mounted() {
handleOpenURL( (appURL) => {
console.log(appURL) // here you can get your appURL path etc and map it to a component... eg path === 'Settings. In this example I've just hardwired it in.
this.$navigateTo(Settings);
});
},
render: h => h("frame", [h(Home)]),
store: ccStore
}).$start();

finally() not working in Vuejs another app

Recently I did this tutorial.
In this app I can successfully run a vuejs app and axios.then.catch.finally or this.form.then.catch.finally.
But I added npm to my old project that was recently upgraded to laravel 5.7.
In my app I can't add finally function. If i do, it says:
Uncaught TypeError: axios.post(...).then(...).catch(...).finally is not a function
My app.js:
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
// require('./bootstrap');
import Vue from 'vue'
window.Vue = Vue
window.axios = require('axios');
import { Form, HasError, AlertError } from 'vform'
window.Form = Form;
Vue.component(HasError.name, HasError)
Vue.component(AlertError.name, AlertError)
Vue.component('pagination', require('laravel-vue-pagination'));
//select 2
import vSelect from 'vue-select'
Vue.component('v-select', vSelect)
//sweet alert 1
import swal1 from 'sweetalert';
window.swal1 = swal1;
import swal from 'sweetalert2'
window.swal = swal;
const toast = swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000
});
window.toast = toast;
/**
* Next, we will create a fresh Vue ap
*
*
* plication instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
Vue.component('timetable-component', require('./components/TimetableComponent.vue'))
/* filter active and inactive */
Vue.filter('activeInactive', function (value) {
if(value==1){
return 'Active'
}else{
return 'Inactive'
}
})
const app = new Vue({
el: '#app',
data:{
},
methods:{
},
mounted(){
}
});
I think my app.js is exactly the same as the tutorial app.js for Form request.
Another thing is that in the tutorial he did not use axios import anywhere but he smoothly used it. But without import, I can't use axios.then.
How did he use it without importing axios?
How can I use finally with then.catch?
a componenet:
loadSite() {
axios
.get("/api/site/list")
.then(({ data }) => {
console.log(data);
this.siteList = data;
})
.catch(function(error) {
console.log(error);
}).finally(()=>{
});
},
As document, to make finally works, you need to add promise.prototype.finally
npm install axios promise.prototype.finally --save
and then
const axios = require('axios');
require('promise.prototype.finally').shim();
axios
.get('http://www.example.com/user')
.then((response) => {
console.log(response.data);
return response;
})
.finally(() => {
console.log('this will always be called');
});
I have the same issue, just solved it by includeing this file
<script src="https://polyfill.io/v3/polyfill.min.js?features=Promise.prototype.finally" defer></script>

Service worker not creating networkFirst Cache

My Service Worker:
importScripts('https://storage.googleapis.com/workbox-
cdn/releases/3.0.0/workbox-sw.js');
//Use Workbox Precache for our static Assets
workbox.precaching.precacheAndRoute([]);
console.log('this is my custom service worker');
//Create articles Cache from online resources
const onlineResources = workbox.strategies.networkFirst({
cacheName: 'articles-cache',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 50,
}),
],
});
workbox.routing.registerRoute('https://newsapi.org/(.*)', args => {
return onlineResources.handle(args);
});
The precache cache works but the onlineResources Cache is never created.
A look at my file structure:
So I don't think scope is an issue even though I cant see clients in my service worker on Chrome dev tools.
Lastly here is my app.js file:
//main populates main tags in indexpage
const main = document.querySelector('main');
//this populates the source dropdown menu with sources
const sourceSelector = document.querySelector('#sourceSelector');
//set default source so page loads this
const defaultSource = 'bbc-news';
//on window load call update news and when update
window.addEventListener('load', async e => {
updateNews();
await updateSources();
sourceSelector.value = defaultSource;
//when sourceSelector is changed update the news with the new source
sourceSelector.addEventListener('change',e =>{
updateNews(e.target.value);
});
//checks for serviceWorker in browser
if('serviceWorker'in navigator){
try{
//if there is register it from a path
navigator.serviceWorker.register('/sw.js');
console.log('registered!');
} catch(error){
console.log('no register!',error);
}
}
});
async function updateNews(source= defaultSource){
//response awaits a fetch of the news API call
const res = await fetch(`https://newsapi.org/v2/top-headlines?sources=${source}&apiKey=82b0c1e5744542bdb8c02b61d6499d8f`);
const json = await res.json();
//fill the html with the retrieved json articles
main.innerHTML = json.articles.map(createArticle).join('\n');
}
//Update the news source
async function updateSources(){
const res = await fetch(`https://newsapi.org/v2/sources?apiKey=82b0c1e5744542bdb8c02b61d6499d8f`);
const json = await res.json();
//Whatever source the sourceSelector picks gets mapped and we take the id of it - It is used with updateNews();
sourceSelector.innerHTML = json.sources
.map(src=>`<option value="${src.id}">${src.name}</option>`).join('\n');
}
function createArticle(article){
return ` <div class="article">
<a href="${article.url}">
<h2>${article.title}</h2>
<img src="${article.urlToImage}">
<p>${article.description}</p>
</a>
</div>
`;
}
App.js plugs into newsAPI and outputs the JSON to the pages HTML.
When you register the route you seem to be trying to use a regex as a string. I think it is literally interpreting the route as a string that includes .*. Instead try the regex /^https:\/\/newsapi\.org/ which per the docs will match from the beginning of the url.

Laravel compact in vue

I want to know how can I pass variables to vue component in laravel?
When we work with blade we can pass variables like:
$now = Carbon::now();
return view('xxxxxxxx', compact('now');
That way I can use $now in xxxxxxxx blade file. But what about vue components? we usually return data by json for components and with axios route we get that info no way to specify such data for exact component of us?
What if I want to use $now = Carbon::now(); in single.vue component?
How can I make that happen?
Update
Here is what I want to do with timing as carbon cannot be used (based on comments) I want to use moment.js
Logic
Let users bid if project deadline hasn't arrived
Don't let users bid if project deadline has arrived
template
<template v-if="`${project.deadline | timeAgo}`">
pssed (will be replaced by button is just for test)
</template>
<template v-else>
still have time (will be replaced by button is just for test)
</template>
script
var moment = require('moment');
export default {
data(){
return {
project : '',
}
},
mounted: function() {
// I found this code by google not sure if is currect!
Vue.filter('timeAgo', function(value){
return moment(value) >= fromNow()
});
},
}
Based on my code above here is the results
Try this:
This is my routes, simply I just render a view with some pre-defined variables
Route::get('/', function () {
return view('welcome', [
'now' => Carbon::now(),
'deadline' => Carbon::now()->addHours(2)
]);
});
And this is my view file. Here I have custom element named: example-component. And this is how I passed PHP variables to Vue component using props.
And pass your data to window like so:
<script>window.data = #json(compact('now', 'deadline'))</script>
And this is my Vue component file:
<template>
<h1>
<span v-if="isPassed">This job is passed</span>
<span v-else>You have to finish this job</span>
{{ parsedDeadline | timeFromX(parsedNow) }}
</h1>
</template>
<script>
const moment = require('moment');
export default {
props: {
now: {
type: String,
default: () => window.data.now.date // since `now` is an object, you need to access the `date` property to get plain string date that moment can parse
},
deadline: {
type: String,
default: () => window.data.deadline.date // same as above
}
},
computed: {
parsedNow () {
return moment(this.now)
},
parsedDeadline () {
return moment(this.deadline)
},
isPassed () {
return this.parsedNow.isAfter(this.parsedDeadline)
}
}
}
</script>
Here's the documentation about computed and filters. You may NEVER add a filter in a mounted function since it may leads to memory leak. Here's how I add my filter. In your app.js (assumed you're using default Laravel Vue preset)
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
Vue.filter('timeFromX', (a, b) => a.from(b)); // TADAAA...!!!
const app = new Vue({
el: '#app'
});
UPDATE
If you want to try this, you may edit the routes/web.php and change the deadline value:
Route::get('/', function () {
return view('welcome', [
'now' => Carbon::now(),
'deadline' => Carbon::now()->subHours(2), // Passed 2 hours ago
// 'deadline' => Carbon::now()->addHours(2), // In 2 hours
]);
});
Checkout the Carbon docs here about addition and subtraction.
UPDATE II
If you got error in app.js from the code above, maybe your transpiler doesn't know about arrow-parens.
// Looks like arrow-parens not working, see code below
// Vue.filter('timeFromX', (a, b) => a.from(b)); // TADAAA...!!!
// Change it to this ???
Vue.filter('timeFromX', function (a, b) {
return a.from(b);
});

React-Redux re-render on dispatch inside HOC not working

I am busy with a little proof of concept where basically the requirement is to have the home page be a login screen when a user has not logged in yet, after which a component with the relevant content is shown instead when the state changes upon successful authentication.
I have to state upfront that I am very new to react and redux and am busy working through a tutorial to get my skills up. However, this tutorial is a bit basic in the sense that it doesn't deal with connecting with a server to get stuff done on it.
My first problem was to get props to be available in the context of the last then of a fetch as I was getting an error that this.props.dispatch was undefined. I used the old javascript trick around that and if I put a console.log in the final then, I can see it is no longer undefined and actually a function as expected.
The problem for me now is that nothing happens when dispatch is called. However, if I manually refresh the page it will display the AuthenticatedPartialPage component as expected because the localstorage got populated.
My understanding is that on dispatch being called, the conditional statement will be reavaluated and AuthenticatedPartialPage should display.
It feels like something is missing, that the dispatch isn't communicating the change back to the parent component and thus nothing happens. Is this correct, and if so, how would I go about wiring up that piece of code?
The HomePage HOC:
import React from 'react';
import { createStore, combineReducers } from 'redux';
import { connect } from 'react-redux';
import AuthenticatedPartialPage from './partials/home-page/authenticated';
import AnonymousPartialPage from './partials/home-page/anonymous';
import { loggedIntoApi, logOutOfApi } from '../actions/authentication';
import authReducer from '../reducers/authentication'
// unconnected stateless react component
const HomePage = (props) => (
<div>
{ !props.auth
? <AnonymousPartialPage />
: <AuthenticatedPartialPage /> }
</div>
);
const mapStateToProps = (state) => {
const store = createStore(
combineReducers({
auth: authReducer
})
);
// When the user logs in, in the Anonymous component, the local storage is set with the response
// of the API when the log in attempt was successful.
const storageAuth = JSON.parse(localStorage.getItem('auth'));
if(storageAuth !== null) {
// Clear auth state in case local storage has been cleaned and thus the user should not be logged in.
store.dispatch(logOutOfApi());
// Make sure the auth info in local storage is contained in the state.auth object.
store.dispatch(loggedIntoApi(...storageAuth))
}
return {
auth: state.auth && state.auth.jwt && storageAuth === null
? state.auth
: storageAuth
};
}
export default connect(mapStateToProps)(HomePage);
with the Anonymous LOC being:
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { loggedIntoApi } from '../../../actions/authentication';
export class AnonymousPartialPage extends React.Component {
constructor(props) {
super(props);
}
onSubmit = (e) => {
e.preventDefault();
const loginData = { ... };
// This is where I thought the problem initially occurred as I
// would get an error that `this.props` was undefined in the final
// then` of the `fetch`. After doing this, however, the error went
// away and I can see that `props.dispatch is no longer undefined
// when using it. Now though, nothing happens.
const props = this.props;
fetch('https://.../api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(loginData)
})
.then(function(response) {
return response.json();
})
.then(function(data) {
if(data && data.jwt) {
props.dispatch(loggedIntoApi(data));
localStorage.setItem('auth', JSON.stringify(data));
}
// else show an error on screen
});
};
render() {
return (
<div>
... onSubmit gets called successfully somewhere in here ...
</div>
);
}
}
export default connect()(AnonymousPartialPage);
the action:
// LOGGED_INTO_API
export const loggedIntoApi = (auth_token) => ({
type: 'LOGGED_INTO_API',
auth: auth_token
});
// LOGGED_OUT_OF_API
export const logOutOfApi = (j) => ({
type: 'LOG_OUT_OF_API'
});
and finally the reducer:
const authDefaultState = { };
export default (state = authDefaultState, action) => {
switch (action.type) {
case 'LOGGED_INTO_API':
// SOLUTION : changed this line "return action.auth;" to this:
return { ...action.auth, time_stamp: new Date().getTime() }
case 'LOG_OUT_OF_API':
return { auth: authDefaultState };
default:
return state;
}
};
My suggestion would be to make sure that the state that you are changing inside Redux is changing according to javascript's equality operator!. There is a really good answer to another question posted that captures this idea here. Basically, you can't mutate an old object and send it back to Redux and hope it will re-render because the equality check with old object will return TRUE and thus Redux thinks that nothing changed! I had to solve this issue by creating an entirely new object with the updated values and sending it through dispatch().
Essentially:
x = {
foo:bar
}
x.foo = "baz"
dispatch(thereWasAChange(x)) // doesn't update because the x_old === x returns TRUE!
Instead I created a new object:
x = {
foo:"bar"
}
y = JSON.parse(JSON.stringify(x)) // creates an entirely new object
dispatch(thereWasAChange(y)) // now it should update x correctly and trigger a rerender
// BE CAREFUL OF THE FOLLOWING!
y = x
dispatch(thereWasAChange(y)) // This WON'T work!!, both y and x reference the SAME OBJECT! and therefore will not trigger a rerender
Hope this helps!

Resources