Submitting a page form results in an ajax call to a backend service which returns an json object. The object is than bound to a vue.js template (a div with a particular id). Everythiong works as expected on the first submit. However, the view is not updated on any following form submits (it still shows the data from the first submit).
<div id="Response"></div>
$('#Form').submit(function (e) {
e.preventDefault();
var $form = $(e.target);
$.ajax({
url: 'https://somewhere,
type: 'POST',
data: $form.serialize(),
dataType: 'json',
success: function(response) {
if (response) {
var app = new Vue({
el: '#Response',
data: response
});
}
}
});
});
How to do this properly so each time the form is submitted, the view is updated appropriately based on the last response?
Now you are creating a new vue instance with each response. You need to mount the vue instance first, then use the response to update the data in it.
Related
I have a page with 2 tabs (Questions and Data) made on Vue and Axios.
In first Tab, I fill the form and submit it - Save button v-on:click="save".
save: function() {
axios({
method: 'patch',
url: url,
data: this.data
})
.then(function (response) {
this.data = response.data;
}
In the second Tab(Data) I have the list of saved data:
mounted() {
axios
.get('/api/recommended-products/?patient_uuid=' + '{{patient.uuid}}')
.then(response => (this.data= response.data.results))
}
Now when I change answers in Questions Tab my list in Data Tab should change automatically. It changes if I refresh the page - mounted() works.
I tried to create updateList() function:
updateList: function() {
axios
.get('/api/recommended-products/?patient_uuid=' + '{{patient.uuid}}')
.then(response => (this.data= response.data.results))
}
and added it to save() function like:
save: function() {
axios({
method: 'patch',
url: url,
data: this.data
})
.then(function (response) {
this.data = response.data;
this.updateList();
}
The problem is that this way works other second time (sometime works sometimes not). So I just added location.reload(); to save() but I don't like this approach. Is it possible to update Data list without refreshing the page? What am I doing wrong with updateList() function?
In my opinion here you should use vuex and its getters.
You would then have only one request in all the application and the data would be automatically refreshed once updated in the state.
You can then access the data using a computed property which will be automatically re-rendered when the state is updated.
Here is an example using multiple tabs : https://codesandbox.io/s/vuex-axios-demo-forked-m0cqe4?file=/src/App.vue
In this example, i'm loading posts information through the JsonPlaceHolder API.
Every time the form is re send (using a function). The action of the store is called, then the state is updated which trigger the getter to re-render the data.
Note: i'm loading the first post into the mounted with a default value of 1 here.
save: function() {
axios({
method: 'patch',
url: url,
data: this.data
})
.then(function (response) {
this.data = […this.data, …response.data]
}
You have re rendered issue I think can can you try above solution
I think this might be helpful. Try to implement something like following.
async function() {
try{
await axios.post() // or any request
//action if success
//another action if success
...
} catch(error) {
//do something with error.
console.log(error)
}
I have a VUE 3 application where we are experiencing some sync issues when clicking on our toggles.
When the toggle is clicked, the app is supposed to call our API with the updated list.
THE PROBLEM:
When the toggle is clicked the data within the computed property is correct. We are then emitting that data to the parent component (data is still correct when received at the parent component).
Parent component calls the API which updates the data. But in the request body, the data is not correct, that is still the old list.
If I click on one of the toggles again the data being sent is then correct from the previous update (it is one click behind).
Here are the steps the app is going through:
A vue component emits computed property to the parent component
// CHILD COMPONENT EMITTING DATA TO PARENT
____filters.vue___
<template>
<ion-toggle
#click="changedFilter"
v-model="filter.selected"
:checked="filter.selected"
slot="end">
</ion-toggle>
</template>
setup(props, context) {
const changedFilter = () => {
console.log(props.searchFiltersArr) ------> **THIS DATA IS CORRECT**
context.emit("changedFilter", props.searchFiltersArr);
};
return {
changedFilter,
filters: props.searchFiltersArr,
};
}
Parent component receives emitted data from the child and calls the API using Axios.
___ SearchFilters.vue _____
<template>
<filters
#changed-filter="updateFilter"
:searchFiltersArr="searchParameters">
</filters>
</template>
export default defineComponent({
name: "SearchFilters",
components: { Filters },
setup() {
const store = useStore();
const searchParameters = computed(() => {
return {
searchParameters: store.state.user.settings.searchParameters,
};
});
async function updateFilter(search: Array<SearchFilter>) {
const headers = {
"Content-type": "application/json",
Authorization:
"Bearer " + "21345",
};
const requestBody = {
user: {
name: "",,
email: "email#email.com",
},
searchParameters: search,
};
console.log(requestBody); -----------> **REQUEST BODY HAS THE CORRECT VALUES FROM CHILD COMPONENT**
await apiClient.put("/settings", requestBody, {
headers,
}); -----> ** REQUEST BODY IN THE ACTUAL REQUEST IS NOT THE UPDATED CONTENT **
}
return {
updateFilter,
searchParameters: searchParameters.value.searchParameters,
};
},
});
The updated data is correct all the way until we call the service. Then the body is incorrect.
How can this be?
If i wrap the axios request inside of a set timeout like so, it works.
setTimeout(function (){
axios service }, 2000)
Let me know if you need any further information.
This is just a simplified example, as this shows the problem. In the real application we are calling a vuex action which then call the api and thereafter commits the updated state. The issue is exatcly the same though.
The problem is somewhat similar to this post - ReactJS - synchronization issue with axios.post
I found a solution to the problem.
Since vue can’t guarantee the order of events (computation should run before click event), I removed the click event and added a watcher instead
While searching in stack overflow .I find an old issue that i am facing too.But no one answered it.
So just wants to know anyone have any idea about it
How to get jquery Tooltipster Plugin to work for newly created DOM elements?
Following is my code
$(document).ready(function() {
$('.test_link').tooltipster({
interactive:true,
content: 'Loading...',
functionBefore: function(origin, continueTooltip) {
continueTooltip();
// next, we want to check if our data has already been cached
//if (origin.data('ajax') !== 'cached') {
$.ajax({
type: 'POST',
url: 'example.php',
success: function(data) {
// update our tooltip content with our returned data and cache it
origin.tooltipster('content', $(data)).data('ajax', 'cached');
}
});
// }
}
});
});
My problem solved.
Just add the instantiation script in the ajax content too.
also set the option multiple:true
ie
$(document).ready(function() {
$('.test_link').tooltipster({
interactive:true,
multiple:true,
content: 'Loading...',
functionBefore: function(origin, continueTooltip) {
continueTooltip();
// next, we want to check if our data has already been cached
//if (origin.data('ajax') !== 'cached') {
$.ajax({
type: 'POST',
url: 'example.php',
success: function(data) {
// update our tooltip content with our returned data and cache it
origin.tooltipster('content', $(data)).data('ajax', 'cached');
}
});
// }
}
});
});
It worked for me in Firefox.But didn't tested in other browser
I know this is an old post, and the problem was solved, but i recently needed something similar.
Adding the initialization on every ajax function was not a solution since we had several content dynamically loaded on the page, so the simplest solution found was:
$(document).on('mouseenter', '[data-toggle="tooltip"]', function(){
if ($(this).is('.tooltipstered')) {
// Do nothing
} else {
$(this).tooltipster({
delay: 50,
// Your other Tooltipster options
});
$(this).mouseover();
}
});
$('[data-toggle="tooltip"]') being the OP's $('.test_link').
The if deter the repeated initialization of document mouseenter.
I'm using Kendo UI Listview control to display Categories data from WCF Service. the problem is always the list view instead of displaying the "Name" of the Category, it display [object Object].
the Json Data returned from the service is like
d
Items
ID=1
Name=Sports
IsActive=true
the HTML code:
<body>
<div data-role="view" data-init="mobileListViewPullWithEndless">
<ul id="grouped-listview"></ul>
</div>
<script>
var categoriesTransport = new kendo.data.RemoteTransport({
read: {
url: "http://localhost:11124/Services/PublishingMobileService.svc/GetAllCategories", //specify the URL which data should return the records. This is the Read method of the Products.svc service.
contentType: "application/json; charset=utf-8", // tells the web service to serialize JSON
dataType: 'json',
type: "POST" //use HTTP POST request as the default GET is not allowed for svc
},
parameterMap: function (data, operation) {
if (operation != "read") {
// web service method parameters need to be send as JSON. The Create, Update and Destroy methods have a "products" parameter.
return JSON.stringify(data);
} else {
return JSON.stringify(data);
}
}
});
function mobileListViewPullWithEndless(e) {
$("#grouped-listview").kendoMobileListView({
height: 400,
dataSource:kendo.data.DataSource.create( {
schema: {
data: "d.Items", // svc services return JSON in the following format { "d": <result> }. Specify how to get the result.
},
transport: categoriesTransport,
template: $("#endless-scrolling-template").text(),
}),
});
}
</script>
<script type="text/x-kendo-tmpl" id="endless-scrolling-template">
<div>
<h3>#:ID#</h3>
</div>
</script>
<script>
var app = new kendo.mobile.Application(document.body);
</script>
Could you please help on that.?
I understand this question is a bit old, but for future reference:
I had this exact issue recently when I bound to an observable without a template. Adding the template as you have gave me the same issue, whereas adding like this works:
<ul id="accomodations-list"
data-role="listview"
data-style="inset"
data-bind="source:accommodations"
data-template="template"></ul>
I have gone through as many questions on here as I could find and tried all the different suggestions and cannot get this to work. I have a view that is bound with Knockout using the mapping plugin and it works okay but only when I do the "wrong thing". Everything that I have read says that you should only make one call to ko.applyBindings() per view and then everything should update using ko.mapping.fromJS(). I cannot seem to get this to work, the only way I have been able to get my view to refresh is to call ko.applyBindings() again in the success call back from my .ajax() call. Here is the offending code.
<script type="text/javascript">
var viewModel;
$(document).ready(function() {
$("#panelbar").kendoPanelBar({
expandMode: "multiple"
});
$.ajax({
type: 'GET',
url: '/Home/IsUserMarketingManager',
success: function (data) {
if (data == true) {
$('#submitNewCase').hide();
$('#approveCase').show();
$('#disapproveCase').show();
}
}
});
// Generate client View Model from Server View Model
viewModel = new ViewModel();
ko.mapping.fromJS(#Html.Raw(Json.Encode(Model)),{}, viewModel);
ko.applyBindings(viewModel);
});
function ViewModel () {
var self = this;
self.addLocation = function() {
self.AdditionalLocations.push({ GaNumber: "" });
};
}
</script>
And later this to update the form with retrieved data:
<script type="text/javascript">
$('#btnImport').click(function () {
$.blockUI({ message: '<h2>Importing Client Information...</h2> <img src="/Images/ajax-loader.gif"><br />' });
$.ajax({
type: 'post',
url: '/Home/ImportClientCrmInfoJson',
dataType: "json",
data: ko.mapping.toJS(viewModel),
success: function (data) {
$.unblockUI();
if (!data.AccountNull) {
ko.mapping.fromJS(data, {}, viewModel);
} else {
alert("Could not find account for this GA Number, please try again.");
}
}
});
});
</script>
When submitting the form to my controller, all the data is there and mapped correctly to my server side View Model, but the form in the view isn't updated with the data that comes back from the $.ajax call. I've gotten the form to update if I do the following, but I know it's not the right way and has caused me other issues as well.
<script type="text/javascript">
$('#btnImport').click(function () {
$.blockUI({ message: '<h2>Importing Client Information...</h2> <img src="/Images/ajax-loader.gif"><br />' });
$.ajax({
type: 'post',
url: '/Home/ImportClientCrmInfoJson',
dataType: "json",
data: ko.mapping.toJS(viewModel),
success: function (data) {
$.unblockUI();
if (!data.AccountNull) {
viewModel = ko.mapping.fromJS(data);
ko.applyBindings(viewModel); // This works but isn't the right way...
} else {
alert("Could not find account for this GA Number, please try again.");
}
}
});
});
</script>
Any help would be much appreciated.
Have you examined that the following line of code appears to create a 'NEW' viewmodel?
viewModel = ko.mapping.fromJS(data);
When you do this the new viewModel the old bindings are destroyed. This is why you have to call ApplyBindings again. Anyway, I think the above line of code is the root of the problem.
Is there a way for you to create an observable property on the viewModel and allow the viewModel to reflect the data in this object? That may be a more practical approach to the update process.
In the success callback of the ajax call, use this method ko.applyBindings(viewModel) but pass as a second parameter the DOM portion you want to update as follows
ko.applyBindings(viewModel, $("#mydiv")[0])
Don't use a jquery object but a REAL DOM object.