how to upload csv file nuxtjs to API - laravel

Nuxt.js I searched lots of tutorials for CSV uploading using laravel API but I did not get logic on how to code csv uploading things help me to solve this or give tutorial links.
Modules
import { AxiosResponse } from "axios";
import { axios } from "#/plugins/axios";
export default {
async importVsim(params: any): Promise<AxiosResponse<null>> {
return await <AxiosResponse>axios.post('v1/ucl/import',params);
}
}
Components
<template>
<div style="display:inline; text-align:left;">
<b-button icon-left="upload" #click="open">UCL CSV</b-button>
<b-modal
v-model="showModal"
trap-focus
aria-role="dialog"
aria-label="Example Modal"
:width="600"
aria-modal>
<div class="card mb-4">
<header class="card-header">
<p class="card-header-title">UCL CSV</p>
</header>
<div class="card-content">
<b-field label="mnk_*.csv">
<b-upload v-model="file1" class="file-label">
<span class="file-cta">
<b-icon class="file-icon" icon="upload"></b-icon>
<span class="file-label">Click to upload</span>
</span>
<span class="file-name" v-if="file1">
{{ file1.name }}
</span>
</b-upload>
</b-field>
<b-field label="htk_*.csv">
<b-upload v-model="file2" class="file-label">
<span class="file-cta">
<b-icon class="file-icon" icon="upload"></b-icon>
<span class="file-label">Click to upload</span>
</span>
<span class="file-name" v-if="file2">
{{ file2.name }}
</span>
</b-upload>
</b-field>
<div style="text-align:center;">
<b-button #click="close" :loading="loading">cancel</b-button>
<b-button class="is-primary" #click="upload" :loading="loading">Ok</b-button>
</div>
</div>
</div>
</b-modal>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "nuxt-property-decorator"
import importCsv from "#/modules/importCsv"
#Component({})
export default class extends Vue {
file1: any = null
file2: any = null
loading: boolean = false
showModal: boolean = false
errors: any = {}
async upload() {
const response = await importCsv.importVsim(this.file2)
console.log(response)
}
open() {
this.errors = {}
this.showModal = true
}
close() {
this.showModal = false
}
}
</script>

Related

How to show/hide #foreach statement

I have a Vuejs 3 dropdown reusable component. My problem is that the #foreach statement runs before the component loads so it causes a flash of the foreach results which is very ugly upon refresh or when the page is loading.
To demonstrate please check this gif:
My component in blade:
<Dropdown title="{{ isset($currentCategory) ? ucwords($currentCategory->name) : 'Categories' }}">
<Dropdowncontent>
<Dropdownitems href="/">
All
</Dropdownitems>
<div>
#foreach ($categories as $category)
<Dropdownitems
href="/?category={{ $category->slug }}&{{ http_build_query(request()->except('category')) }}"
class="{{ isset($currentCategory) && $currentCategory->is($category) ? ' selectedCategoryItem' : '' }}">
{{ $category->name }}
</Dropdownitems>
#endforeach
</div>
</Dropdowncontent>
</Dropdown>
I added a div to contain the #foreach statement but i don't know what to do from here. I don't want to use alpineJS as it will defeat the purpose of using Vue (I guess?).
I just need a way to only display this div or the #foreach statement if the component is fully loaded or if the button is pressed or something like that. Any ideas?
-- EDIT --
I tried to hide the links in my 'dropdownitems' vue component and set the default value to false. The links are now hidden but still the blade #foreach statement echoing out the results as text before the component is loaded:
<template>
<a v-if="showLinks" href="" class="demogard categoryItems">
<slot />
</a>
</template>
<script>
export default {
name: "Dropdownitems",
setup() {
const showLinks = false;
return {
showLinks,
};
},
};
</script>
<style></style>
Here is a gif to show the result of that:
-- EDIT --
Here is my dropdown component:
<template>
<div
class="relative"
v-click-outside="onClickOutside"
#click="showCategories"
>
<slot name="toggler">
<button
class="flex max-h-52 w-full overflow-auto py-2 pl-3 pr-9 text-sm font-semibold lg:inline-flex lg:w-32"
>
{{ title }}
</button>
</slot>
<slot />
</div>
</template>
<script>
import vClickOutside from "click-outside-vue3";
import { ref, onMounted, provide } from "vue";
export default {
name: "Dropdown",
props: ["title"],
directives: {
clickOutside: vClickOutside.directive,
},
setup() {
const sharedState = ref(false);
const showCategories = () => {
sharedState.value = !sharedState.value;
};
const onClickOutside = (event) => {
sharedState.value = false;
};
provide("sharedState", sharedState);
return {
sharedState,
showCategories,
onClickOutside,
};
},
};
</script>
<style></style>
As your question, I think you have to add if condition on your dropdown component.
Your dropdown component should be like this
#dropdown.vue
<template>
<div class="dropdown">
<div #click="show = !show">{{title}}</div>
<div v-if="show">
<slot />
</div>
</div>
</template>
<script>
import { ref } from "vue";
export default {
props: ["title"],
setup(props) {
const show = ref(false);
return {
show,
};
},
};
</script>
Demo
---- EDIT ----
#dropdown.vue
<template>
<div
class="relative"
v-click-outside="sharedState = false"
>
<slot name="toggler">
<button
class="flex max-h-52 w-full overflow-auto py-2 pl-3 pr-9 text-sm font-semibold lg:inline-flex lg:w-32"
#click="sharedState = !sharedState"
>
{{ title }}
</button>
</slot>
<div v-if="sharedState">
<slot />
</div>
</div>
</template>
<script>
import vClickOutside from "click-outside-vue3";
import { ref, onMounted, provide } from "vue";
export default {
name: "Dropdown",
props: ["title"],
directives: {
clickOutside: vClickOutside.directive,
},
setup() {
const sharedState = ref(false);
// const showCategories = () => {
// sharedState.value = !sharedState.value;
// };
// const onClickOutside = (event) => {
// sharedState.value = false;
// };
provide("sharedState", sharedState);
return {
sharedState,
//showCategories,
//onClickOutside,
};
},
};
</script>
<style></style>
Try with a #if directive:
Conditional Rendering
from the documentation:
<button #click="awesome = !awesome">Toggle</button>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
As showed in the example it render the "h1" tag conditionally respect the "awesome" variable.
In this case i will set a default value of "false" and i will turn it to "true" in the mounted hook:
Lifecycle
It's impossible to load Vue before PHP because your webpage only displays when full PHP code is received from the server. Therefore, we're never able to stop PHP or HTML from flashing if we're using them inside a reusable Vue component.
The solution I made is simply passing the value of the foreach loop as a prop to the Vue component in order for it to be displayed from there, not from my blade file.
Here's my code in blade after passing the value of the category name as a prop to my Vue component.
<Dropdown title="{{ isset($currentCategory) ? ucwords($currentCategory->name) : 'Categories' }}">
<Dropdowncontent>
<Dropdownitems href="/" category="All"></Dropdownitems>
#foreach ($categories as $category)
<Dropdownitems
category="{{ $category->name }}"
href="/?category={{ $category->slug }}&{{ http_build_query(request()->except('category')) }}"
class="{{ isset($currentCategory) && $currentCategory->is($category) ? ' selectedCategoryItem' : '' }}">
</Dropdownitems>
#endforeach
</Dropdowncontent>
</Dropdown>
Here is me displaying it from there the Vue dropdown items component:
<template>
<a href="" class="demogard categoryItems">
<slot>{{ category }}</slot>
</a>
</template>
<script>
export default {
name: "Dropdownitems",
props: ["category"],
};
</script>
<style></style>

Active user does not show in real time chat app

I am following up this guide https://www.codechief.org/article/real-time-chat-app-with-laravel-6-vue-js-and-pusher#gsc.tab=0 to create real-time chat app in Laravel and Vue.
But it does not show list of active user.
Also this span never shows
<span class="text-muted" v-if="activeUser" >{{ activeUser.first_name }}` is typing...</span>
Also, this method does not work properly because in console log it shows undefined is typing...
sendTypingEvent() {
Echo.join('chat')
.whisper('typing', this.user);
console.log(this.user.fist_name + ' is typing now')
}
And it is not actually real time, because I see new messages only if I reload page.
This is Vue component
<template>
<div class="row">
<div class="col-8">
<div class="card card-default">
<div class="card-header">Messages</div>
<div class="card-body p-0">
<ul class="list-unstyled" style="height:300px; overflow-y:scroll" v-chat-scroll>
<li class="p-2" v-for="(message, index) in messages" :key="index" >
<strong>{{ message.user.first_name }}</strong>
{{ message.message }}
</li>
</ul>
</div>
<input
#keydown="sendTypingEvent"
#keyup.enter="sendMessage"
v-model="newMessage"
type="text"
name="message"
placeholder="Enter your message..."
class="form-control">
</div>
<span class="text-muted" v-if="activeUser" >{{ activeUser.first_name }} is typing...</span>
</div>
<div class="col-4">
<div class="card card-default">
<div class="card-header">Active Users</div>
<div class="card-body">
<ul>
<li class="py-2" v-for="(user, index) in users" :key="index">
{{ user.first_name }}
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props:['user'],
data() {
return {
messages: [],
newMessage: '',
users:[],
activeUser: false,
typingTimer: false,
}
},
created() {
this.fetchMessages();
Echo.join('chat')
.here(user => {
this.users = user;
})
.joining(user => {
this.users.push(user);
})
.leaving(user => {
this.users = this.users.filter(u => u.id != user.id);
})
.listen('ChatEvent',(event) => {
this.messages.push(event.chat);
})
.listenForWhisper('typing', user => {
this.activeUser = user;
if(this.typingTimer) {
clearTimeout(this.typingTimer);
}
this.typingTimer = setTimeout(() => {
this.activeUser = false;
}, 1000);
})
},
methods: {
fetchMessages() {
axios.get('messages').then(response => {
this.messages = response.data;
})
},
sendMessage() {
this.messages.push({
user: this.user,
message: this.newMessage
});
axios.post('messages', {message: this.newMessage});
this.newMessage = '';
},
sendTypingEvent() {
Echo.join('chat')
.whisper('typing', this.user);
console.log(this.user.fist_name + ' is typing now')
}
}
}
</script>
"Also, this method does not work properly because in console log it shows undefined is typing..."
i assume you made a typo in your console.log, you probably meant:
this.user.first_name
Concerning your "realtime" problem, i suspect it might be because your broadcasted Event is being queued, so you might want to use the ShouldBroadcastNow instead of ShouldBroadcast

infinite scroll using laravel and vue request not sent to display data

good day;
i new in vue.js
i have simple problem when i using infinite scroll i make configuration as below but when page reloaded it must send request to data base to show data when page =1 this request not sent
i want help to get it work
this is my
this is service component
<template>
<div>
<!-- start covr-page --------------------- -->
<div class="covr-page">
<h2>خدمات لوجستية متكاملة </h2>
<div class="overlay"></div>
</div>
<!-- end covr-page --------------------- -->
<!-- start servic --------------------- -->
<div class="servic sections">
<div class="container">
<h3 class="start-title">
<img src="/images/start-title.png" alt="">
خدمات لوجستية متكاملة
</h3>
<div class="row">
<div v-for="service,key in list" class="col-lg-offset-3 col-lg-6 col-md-12 col-md-8 col-sm-offset-1 col-sm-10">
<a href="order-service.html">
<div class="email-signature">
<div class="signature-details">
<div class="signature-img">
<img :src="`upload/${service.icon}`" alt="">
</div>
</div>
<div class="contant-serv">
<h4>{{service.ar_name}}</h4>
<p>
{{service.ar_description}}
</p>
</div>
</div>
</a>
</div>
<infinite-loading #distance="100" #infinite="infiniteHandler"></infinite-loading>
</div>
</div>
</div>
</div>
</template>
this is my route
Route::get('/Services', 'ServicesController#Services');
this is my js code
<script>
export default {
name: "Services",
data: function () {
return {
list: [],
page:1
}
},
mounted(){
// this.infiniteHandler()
// axios.get('/Services')
// .then((response) =>{
// this.list=response.data
// }).catch((error) =>this.errors=error.response.data.errors );
},
methods: {
infiniteHandler($state) {
this.$http.get('/Services?page='+this.page)
.then(response => {
return response.json();
}).then(data => {
$.each(data.data, (key, value)=> {
this.list.push(value);
});
$state.loaded();
});
this.page = this.page + 1;
},
},
}
</script>
you have not declared vue-infinite-loading
import InfiniteLoading from 'vue-infinite-loading';
export default {
components: {
InfiniteLoading,
},

displaying laravel show method on vue component

i have a list of movies am trying to display the details of one movie using the show method
here is my component for all movies
<template>
<div>
<el-row :gutter="10">
<el-col :span="6" v-for="movie in movies" v-bind:key="movie">
<el-card shadow="always" :body-style="{ padding: '0px'} ">
<img v-bind:src="movie.cover_photo" class="image" >
<div style="padding: 14px;">
<div class="bottom clearfix">
<router-link :to="{name:'details',params:{id:movie.id}}">{{movie.title}}</router-link>
<router-view></router-view>
<h4>{{ movie.year }}</h4>
<h4>{{ movie.type }}</h4>
</div>
<div class="block">
<el-rate :max="10" ></el-rate>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
movies: [],
movie:{
id:'',
}
};
},
created(){
this. fetchMovieList();
this.showMovie
},
methods: {
fetchMovieList() {
axios.get('/movies').then(response => {
this.movies = response.data;
})
.catch(error=>console.log(error))
},
showMovie(id){
axios.get('/movies/'+id).then((res)=>{
if(res.data.status==true){
this.movie= res.data.movie;
console.log(res.data.movie)
}else{
alert('No Movie founded with this id')
}
})
.catch((err)=>{alert('error')})
}
}
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>
my show method:
public function show($id)
{
$movie=Movie::find($id);
if($movie){
return response()->json(['status'=>true,'movie'=>$movie]);
}else{
return response()->json(['status'=>false]);
}
}
my router on app.js:
const movie=Vue.component('details', require('./components/DetailsComponent.vue').default);
/**
* 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.
*/
const router=new VueRouter({
mode:'history',
routes:[
{
path:'/movie/:id',
name:'movie',
component:movie
},
],
});
const app = new Vue({
el: '#app',
router,
});
when i click on the router link it just changes the url to the id of the movie but it doesnt show the component with details when i hit the show endpoint with a specific id it returns the movie in json format on the browser
I think your variable of v-for conflict with the same variable of data().
You should try another variable name of v-for.
Something like
<el-col :span="6" v-for="value in movies" v-bind:key="movie">
<el-card shadow="always" :body-style="{ padding: '0px'} ">
<img v-bind:src="value.cover_photo" class="image" >
<div style="padding: 14px;">
<div class="bottom clearfix">
<router-link :to="{name:'details',params:{id:value.id}}">{{value.title}}</router-link>
<router-view></router-view>
<h4>{{ value.year }}</h4>
<h4>{{ value.type }}</h4>
</div>
<div class="block">
<el-rate :max="10" ></el-rate>
</div>
</div>
</el-card>
</el-col>
Hope this helps you: Reacting to Params Changes
Regards,

Getting details from vue component in laravel

I have a Laravel 5.4 project.
I have created two components : Students.vue and Student.vue component
Students.vue get all the students and Student.vue the markup for one display of a student
here is my Students.vue
<template>
<div v-if = "students.length && meta">
<pages :pagination = "meta"></pages>
<div class = "col-lg-3 col-sm-6 col-md-4 music_genre" v-for = "student in students">
<student :student = "student"></student>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import eventHub from '../../events.js'
export default {
methods: {
...mapActions({
getStudents: 'student/getStudents'
})
},
computed : {
...mapGetters ({
students : 'student/students',
meta : 'student/meta'
})
},
mounted() {
this.getStudents(1)
}
}
</script>
here is my Student.vue
<template>
<div class="">
<div class="team-info ">
<h4>
<a href="#">
{{student.name}} {{student.last_name}}
</a>
</h4>
<span class='team-member-edit'>
<i class='fa fa-pencil icon-xs'></i>
</span>
</div>
<p>Along with studies, is good in all around activities held in the university events.</p>
</div>
</template>
<script>
export default {
props:['student'],
mounted() {
}
}
</script>
When i click on the Student Name, I would like to display all the details of the student. How to achieve that
I assume you have a key differentiating each students, hence you can do this
'/students/:id': {
component: 'student'
}

Resources