This is my Indexing.vue component.
<div>
<div v-for="data in indexingList" :key="data.indexing_id">
<p>{{ data.indexing_name }}</p>
<p>{{ data.indexing_url }}</p>
</div>
<base-button type="primary" size="sm" #click="deleteIndexing(data.indexing_id)">Delete
</base-button>
</div>
export default {
data() {
return {
indexingList: [],
}
},
methods: {
getIndexingList: function() {
this.api.getDataModule("indexing/" + store.state.journalId, "journals/v1/")
.then((res) => {
console.log(res.data);
this.indexingList = res.data.indexingList;
},
(err) => {
console.log(err);
}
);
},
deleteIndexing: function(dVal) {
let sVal = {};
sVal.indexing_id = dVal;
this.api.putData("indexing/" + store.state.journalId + "/deleteindexing", sVal)
.then((res) => {
console.log(res.data);
},
(error) => {
console.log(error);
}
);
},
},
mounted: function() {
this.getIndexingList();
},
}
I'm getting data from the server using getIndexingList function in the form of the API get method. And removing the data once the user clicks the delete button by using the deleteIndexing function in the form of the put API method.
We wrote APIs in a separate file. Here in indexing.vue we are just passing the APIs.
Now I want to fix the delete(remove) function. The data was removed from the database once the user clicks the delete button but it is not removed from the webpage. Every time I need to refresh the page to see the changes.
You can use Vue.delete (this.$delete) which also ensure that the deletion triggers the view updates.
Try this-
deleteIndexing: function(dVal) {
let sVal = {};
sVal.indexing_id = dVal;
this.api
.putData("indexing/" + store.state.journalId + "/deleteindexing", sVal)
.then(
(res) => {
// find the item from indexingList and remove it
// Also make sure your response has the id of the deleted item
let index = this.indexingList.findIndex(item => item.id == res.id);
if (index != -1) {
this.$delete(this.indexingList, index);
}
},
(error) => {
console.log(error);
},
);
},
Related
I have this Vue JS tabs:
<b-tabs v-model="tabIndex">
<b-tab title="Settings">
<validation-observer ref="validateSetting" tag="form">
my htmlform......
<b-button variant="primary" type="submit" #click.prevent="validateSetting"> Next </b-button>
</validation-observer>
</b-tab>
<b-tab title="Edit Mapping" :disabled="mapingDisabled">
<validation-observer ref="validateEditMapping" tag="form">
my htmlform......
<b-button variant="primary" type="submit" #click.prevent="validateEditMapping"> Next Steps </b-button>
</validation-observer>
</b-tab>
<b-tab title="Safety" :disabled="safetyDisable">
<b-button variant="primary" type="submit" #click.prevent="submitXml" > Submit </b-button>
</b-tab>
</b-tabs>
Each tab contain HTML form which is validating using validation-observer means user can't go to next tab until the current tab validation is done.
Here on the second and third I have disabled it using :disabled="mapingDisabled" and :disabled="safetyDisable".
Now, If I click on the button of the first tab it's not immediately go to the second tab ! I have to click again to go to the second and so one... why?
Here is what I am using on the script part:
On the data property I have this 2 property:
mapingDisabled: true,
safetyDisable: true,
tabIndex: 1,
and the methods:
validateSetting() {
this.$refs.validateSetting.validate().then((success) => {
if (success) {
this.mapingDisabled = false;
this.tabIndex++;
let _this = this;
if (this.countHTTP == 0) {
this.callHttp();
this.countHTTP++;
}
}
});
},
callHttp() {
let importData = {
token: this.mappingData.token,
xml_file_url: this.mappingData.xml_file_url,
name: this.mappingData.mapping_name,
encoding : this.mappingData.encoding,
};
http.post("projects/import/", importData)
.then((response) => {
let res = response.data;
let _this = this;
if (res.status !== 1) {
setTimeout(function () {
_this.callHttp();
this.loadDone = true;
}, 5000);
} else if (res.status === 1) {
this.loadDone = false;
this.mappingData.id_feed = res.id_feed;
res.field_names.forEach(function (item, index) {
_this.mappingData.projectFieldOptions.push({
value: item,
text: item,
custom: false,
});
});
}
})
.catch((error) => {
console.log(error);
});
},
validateEditMapping() {
this.$refs.validateEditMapping.validate().then((success) => {
if (success) {
this.tabIndex++;
this.safetyDisable = false;
}
});
},
submitXml() {
http.post("projects/import/mapping/", this.mappingData)
.then((response) => {
for (const prop of Object.getOwnPropertyNames(this.mappingData)) {
delete this.mappingData[prop];
}
this.$bvModal.hide("import-xml-modal");
})
.catch((error) => {
console.log(error);
});
},
I think so "this.tabIndex++;" should be "this.tabIndex += 1;".But I haven't tested it,You can try it.
I'm trying to pass data from vue component to blade file. I try to create props but it's didn't work for me. Is it any possible to pass the object to props to get the data? I'm new laravel. I want to pass data which subject, message, days, condition and module name to blade file(view).
I kept searching for this but couldn't find an answer that will make this clear.
Thanks!
blade.php
<div id="app">
<email-component
email_edit_route="{{ route('havence.automail.edit',['id'=>$mailTemplates->id]) }}"
>
</email-component>
</div>
Vue.js
<script>
import Vue from 'vue'
import axios from 'axios'
import MarkdownIt from 'markdown-it'
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
var msg_editor;
const md = new MarkdownIt({
linkify: true
})
export default {
props: ['email_creation_link', 'email_index_route', 'email_edit_route','conditions','modules'],
components: {
},
data() {
return {
template: {
subject: '',
message: '' ,
days: '',
condition_id: 1,
},
options:[
{
display:'Client Name',
actual:'Client name'
},
{
display:'Joined Date',
actual:'Joined date'
},
{
display:'Module Name',
actual:'Module name'
},
{
display:'Last Seen',
actual:'Last seen'
},
],
showName: false,
}
},
mounted(){
var self = this;
ClassicEditor
.create(document.querySelector( "#msg"),
{
})
.then(editor => {
msg_editor = editor;
editor.model.document.on( 'change:data', () => {
self.template.message = msg_editor.getData();
});
})
.catch(error => {
console.error(error);
})
},
methods: {
//Drag items
dragstart: function(item, e){
this.draggingItem = item;
e.dataTransfer.setData('text/plain', item.actual);
},
dragend: function(item,e) {
e.target.style.opacity = 1;
},
dragenter: function(item, e) {
this.draggingItem = item;
},
//content
replaceVariables(input)
{
let updated = input
return updated
},
//hidecontent
showHide: function(e)
{
console.log("Show "+e.target.value+ " fields")
this.showName = e.target.value !== ''
},
fetch()
{
//request data
axios.get(this.email_index_route,this.template)
.then((res) => {
this.template = res.data.template;
})
},
save()
{
//save data to db
axios.post(this.email_index_route, this.templates)
.then((res) => {
alert('Mail sent successfull!')
})
},
addToMail: function(type, text)
{
if (type == 'message') {
this.template.message += text;
msg_editor.setData(this.template.message);
}
},
//user name replace
replaceVariables() {
return this.replaceVariables(this.options || '')
},
}
}
</script>
Quick solution. : why not store data in local storage and fetch it from laravel blade ?
Next solution: you can fire global event from vue and listen on laravel blade .
why dont you send the data through ajax post call and get the data from the controller ?
then pass the data object to blade template.
I have a custom component which receives a list of filters in order to display just the doctors that the user has selected:
<DoctorsSidebarFilter #update-view='showFilteredDoctors'></DoctorsSidebarFilter>
Next, in my main component, I'm using this to display the doctors:
<v-flex
v-for="doctor in allDoctors"
:key="doctor.first_name"
xs12
sm6
md4
>
And here's my data:
export default {
data: () => ({
allDoctors:[],
}),
methods: {
fetchDoctors(){
//Retrieve doctors
this.$store.dispatch(RETRIEVE_DOCTORS)
.then(
response => {
this.allDoctors = response;
}
)//TODO-me: Handle the error properly!
.catch(error => {
console.log(error);
});
},
showFilteredDoctors(filters){
let result = [];
this.fetchDoctors();
console.log('1:' + " " + JSON.stringify(this.allDoctors));
if (filters.length > 0) { // If Array is not empty then apply the filters
console.log('2');
this.allDoctors.forEach(function(e) {
if(filters.some(s => s.specialty === e.specialty || s.city === e.city)) {
result.push(e);
}
});
console.log('3:' + " " + JSON.stringify(result));
this.allDoctors = [...result];
console.log('4:' + " " + JSON.stringify(this.allDoctors));
}
}
},
mounted() {
this.fetchDoctors();
}
}
The problem is that eventhough my filtering works correctly and I can see from console.log('4:' + " " + JSON.stringify(this.allDoctors)); that this.allDoctors contains the new, filtered list; this is never displayed on screen.
Instead I see the default list of doctors that I've fetched from my API. Using vue devtools I can see that the this.allDoctors is momentarily updated with the correct values but then it goes back to the default ones.
As #user1521685 has already explained, the call to fetchDoctors is asynchronous so it'll complete after you've performed the filtering.
Typically you'd do something like this using a computed property instead and only make the server call once.
export default {
data: () => ({
allDoctors: [],
filters: []
}),
computed: {
filteredDoctors() {
const allDoctors = this.allDoctors;
const filters = this.filters;
if (filters.length === 0) {
return allDoctors;
}
return allDoctors.filter(doctor => {
return filters.some(filter => filter.specialty === doctor.specialty || filter.city === doctor.city);
});
}
},
methods: {
fetchDoctors(){
//Retrieve doctors
this.$store.dispatch(RETRIEVE_DOCTORS)
.then(
response => {
this.allDoctors = response;
}
)//TODO-me: Handle the error properly!
.catch(error => {
console.log(error);
});
},
showFilteredDoctors(filters){
this.filters = filters;
}
},
mounted() {
this.fetchDoctors();
}
}
In your template you'd then use:
v-for="doctor in filteredDoctors"
fetchDoctors is async, so in showFilteredDoctors you fetch the doctors, then set the filtered array and then the thenable in fetchDoctors kicks in and overrides the doctors again: this.allDoctors = response.
You'd have to return the Promise in fetchDoctors and use it in showFilteredDoctors like so:
this.fetchDoctors().then(() => /* do the filtering */)
EDIT: Return the Promise like this:
return this.$store.dispatch(RETRIEVE_DOCTORS).then().catch()
I make a component, which show information from database in table. But this information with filters.
Filtering can be by event type and by participant (id: integer type).
When I click the button, I call handleShowClick(). In this function I check: if value of type event isn't null, I get from database events with this type. if value of type event is null, I get all events.
After this I check a participant value. If value isn't null, I call function, which search which events are include this participant. Data from this.state.event show in table in another component.
I haven't problems with event type. But I have problem with participant. When I choose one of participant, table shows correct data for a split second. After this return to prev state (without filter by participants).
How can I fix this issue? I set state to event only in this component
class TestPage extends Component {
constructor(props) {
super(props);
this.state = {
event: [],
searchByType: null,
searchByParticipant: null,
participantToEvent: []
};
this.handleShowClick = this.handleShowClick.bind(this);
this.onHandleEventByTypeFetch = this.onHandleEventByTypeFetch.bind(this);
this.handleParticipantSearch = this.handleParticipantSearch.bind(this);
this.onHandleEventFetch = this.onHandleEventFetch.bind(this);
}
handleShowClick() { // onClick
if (this.state.searchByType !== null) {
this.onHandleEventByTypeFetch(); // select * from ... where type=...
} else {
this.onHandleEventFetch(); // select * from ...
}
if (this.state.searchByParticipant !== null) {
this.handleParticipantSearch();
}
}
handleParticipantSearch() {
const list = [];
this.state.participantToEvent.map(itemP => { // participantToEvent is binding table
if (itemP.parid === this.state.searchByParticipant) {
this.state.event.map(itemEvent => {
if (itemEvent.id === itemP.eventid) {
list.push(itemEvent);
}
});
}
});
console.log(list); // here I see array with correct result
this.setState({ event: list });
}
onHandleEventFetch() {
fetch( ... , {
method: 'GET'
})
.then((response) => {
if (response.status >= 400) {
throw new Error('Bad response from server');
}
return response.json();
})
.then(data => {
if (data.length === 0) {
alert('nothing');
} else {
this.setState({
event: data
});
}
});
}
onHandleEventByTypeFetch() {
fetch( ... , {
method: 'GET'
})
.then((response) => {
if (response.status >= 400) {
throw new Error('Bad response from server');
}
return response.json();
})
.then(data => {
if (data.length === 0) {
alert('nothing');
} else {
this.setState({
event: data
});
}
});
...
}
}
Structure of this.state.event:
[{id: 1, name: 'New event', participant: 5, type: 10}, ...]
Structure of this.state.participantToEvent:
[{id: 1, idparticipant: 5, idevent: 1}, ...]
this.setState(...this.state,{ event: list });
I think this would solve your problem. Because you clear every item except for {event:list} by not copying the previous state.
Edit:
You should put
...this.state
to onHandleEventByeTypeFetch and onHandleEventFetch. Without them when you click handleShowClick one of those two functions always work and clears searchByParticipant data from the state by not copying the previous state.
The reason for you see the correct data for a short time is all about async nature of the state.
I'm stuck at a crossroads with a component I am working on.
I have the following component "RecentUpdates"
Within it I am passing props down to a few other components, as you can see from the top of the file.
My problem is when adding a new post, I can not figure out how to get the correct update object array back and i also can not figure out the correct 'Vue way' to update the data prop that is being passed down to the "PostList" component.
<template>
<div>
<PostFilter v-on:selectedCategory="getSelectedPosts" v-on:showAllPosts="showAllPosts" :user="user" :categories="categories"/>
<PostList v-if="recent_posts[0]" :categories="categories" :posts="recent_posts[0]" :user="user"/>
<Pagination v-on:getPreviousPage="getPreviousPage" v-on:getNextPage="getNextPage"/>
</div>
</template>
<script>
import PostList from './PostList';
import PostFilter from './PostFilter';
import Pagination from './Pagination';
import EventBus from '../event-bus';
export default {
name: 'RecentUpdates',
data: () => ({
errors: [],
recent_posts: [],
}),
props: ['categories', 'user'],
components: {
PostList,
PostFilter,
Pagination
},
created() {
if (this.user.meta.selected_categories[0] == 0) {
this.showAllPosts();
}
// do not call here, not working as expected
// is switching selected category to an incorrect one
// this.updateList();
this.getSelectedCategory();
},
watch: {
recent_posts: function(newValue) {
EventBus.$on('addPost', function(newPost) {
console.log(newPost);
this.$forceUpdate();
//this.recent_posts.push(newPost);
//this.$set(this.recent_posts, newPost, newPost);
// this.$nextTick(function () {
// this.recent_posts.push(newPost);
// });
});
console.log(this.recent_posts[0]);
// this.$nextTick(function () {
// console.log(this.recent_posts[0]) // => 'updated'
// });
// if (this.user.meta.selected_categories[0] == 0) {
// EventBus.$on('addPost', this.showAllPosts);
// } else {
// EventBus.$on('addPost', this.getSelectedCategory);
// }
//this.updateList();
}
},
methods: {
// updateList() {
// if (this.user.meta.selected_categories[0] == 0) {
// EventBus.$on('addPost', this.showAllPosts);
// //EventBus.$emit('newPost');
// } else {
// EventBus.$on('addPost', this.getSelectedCategory);
// //EventBus.$emit('newPost');
// }
// },
getSelectedCategory() {
let categoryId = this.user.meta.selected_categories[0];
this.getSelectedPosts(categoryId);
},
showAllPosts() {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]',
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = [];
//this.recent_posts = response.data;
//console.log(response.data);
this.recent_posts.push(response.data);
console.log(this.recent_posts[0]);
})
.catch(e => {
this.errors.push(e);
});
},
getSelectedPosts(categoryId) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = [];
//console.log(response.data);
this.recent_posts.push(response.data);
console.log(this.recent_posts[0]);
})
.catch(e => {
this.errors.push(e);
});
},
/**
* Pagination methods
*
*/
getPreviousPage(page) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = response.data;
})
.catch(e => {
this.errors.push(e);
});
},
getNextPage(page) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = response.data;
})
.catch(e => {
this.errors.push(e);
});
}
},
}
</script>
<style>
</style>
So there are a number of issues I see reading through your code.
You have a recent_posts data property, which is an array. When you make your ajax call to get the posts you push the response which is also an array into the recent_posts array. Why? Why not just set recent_posts = response.data? Then you won't have to be passing recent_posts[0] around.
You're setting up your EventBus handler inside a watcher. This is really unusual. Typically you would set up a handler inside created or mounted.
this inside the EventBus handler likely refers to the EventBus and not your Vue. Ideally, you would set the handler to be a method on the component, which is already bound to the Vue. Something like EventBus.$on("addPost", this.addPost).
Once you've done all that, adding a new post should be as simple as this.recent_posts.push(newPost).
Here is what I might recommend.
export default {
name: 'RecentUpdates',
data(){
return {
errors: [],
recent_posts: []
}
},
props: ['categories', 'user'],
components: {
PostList,
PostFilter,
Pagination
},
created() {
if (this.user.meta.selected_categories[0] == 0) {
this.showAllPosts();
}
this.getSelectedCategory();
EventBus.$on("addPost", this.addPost)
},
beforeDestroy(){
EventBus.$off("addPost", this.addPost)
},
methods: {
getPosts(url){
axios.get(url, {headers: {'X-WP-Nonce': portal.nonce}})
.then(response => this.recent_posts = response.data)
.catch(e => this.errors.push(e))
},
showAllPosts() {
const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]';
this.getPosts(url);
},
getSelectedPosts(categoryId) {
const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId;
this.getPosts(url);
},
addPost(newPost){
this.recent_posts.push(newPost)
},
... //other methods
},
}
Try using kebab-case in your event listeners instead of camelCase:
Example: v-on:selectedCategory="getSelectedPosts" should be v-on:selected-category="getSelectedPosts".
Example: v-on:showAllPosts="showAllPosts" should be v-on:show-all-posts="showAllPosts" or even using the shortcut #show-all-posts="showAllPosts".
UPDATE: If you can provide the code of the other components so we can have a clearer vision of your problem, But you only want to track changes that happens on an object or an array in vue.js you need to deep watch them.
your watcher should be :
watch: {
recent_posts: {
deep: true,
handler: function( oldValue, newValue) {
console.log( "recent_posts has changed" );
// A post has been added, updated or even deleted
}
}
}