Regularly send POST request when user changes value in <textarea> - javascript

I created a form in which user puts some food names to the menu in textarea and then he/she can press button to submit this form and send a POST request. After submitting, all data from textareas (there are 20 of them) is being sent to mongoDB. It works absolutely fine.
The problem is: it takes time for user to fill all 20 textareas, so i wanted to make some kind of "autosave", just in case browser stops working or other errors occur and to prevent data loss.
Data must be sent to database every time changes occur in the textarea. How is it possible to send POST request from form without clicking submit button and just by changing value of textarea.
<form method="POST" action="/">
<table>
<caption style="margin-bottom: 20px; font-size: 2em"><b>MENÜÜ</b></caption>
<tr>
<td style="column-span: 2; border: none; font-size: 0.8em">ESMASPÄEV</td>
</tr>
<tr>
<td class="hommikusook">Hoomikusöök</td>
<td class="userinput"><textarea name="MondayBreakfast" class="textarea" placeholder="Kirjuta siia" autofocus></textarea></td>
</tr>
<tr>
<td class="vitamiiniamps">Vitamiiniamps</td>
<td class="userinput"><textarea name="MondayVitamin" class="textarea" placeholder="Kirjuta siia"></textarea>
</td>
</tr>
<tr>
<td class="louna">Lõunasöök</td>
<td class="userinput"><textarea name="MondayLunch" class="textarea textarealong" placeholder="Kirjuta siia"></textarea></td>
</tr>
<tr>
<td class="oode">Oode</td>
<td class="userinput"><textarea name="MondayOode" class="textarea" placeholder="Kirjuta siia"></textarea>
</td>
</tr>
</table>
<button type="submit">Submit</button>
</form>
I tried adding eventListener in frontend JS file and i managed to console.log these value of the textarea everytime it is being changed, but don't know how to send them to the backend so i could add this to Database.
var numberOfTextAreas = document.querySelectorAll('.textarea').length;
for (var i = 0; i < numberOfTextAreas; i++) {
document.querySelectorAll(".textarea")[i].addEventListener("change", function () {
console.log('New value: ', this.value);
console.log('Name: ', this.name);
});
}
For backend is used express.
Thanks!

You need to use fetch API or AJAX. So every time the user changes you have to call this function:
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
// Then you call the function like this:
postData('https://example.com/autosave', { text: 'This is the text I want to save' })
.then(data => {
// Autosaved successfully!
});
I would recommend debounce this function or call it every time the user blurs the textarea (performance reasons).

Auto-Save forms components are using the onchange (and/or onkeyup and/or onkeydown) attribute to register to the event and call the save method.
In addition, there is the issue of triggering to many requests. This can be solved by setTimeout and clearTimeout;
The code will look something like this (pseudo-code):
//HTML
<form method="POST" action="/" name="myForm">
<textarea name="textareaName_1" onchange="handleAutoSave"></textarea>
<textarea name="textareaName_2" onchange="handleAutoSave"></textarea>
...
</form>
// JS
var autoSaveProgress = null;
function handleAutoSave() {
var formData = new FormData(document.querySelector('[name]="myForm"'));
// cancel last request
if(autoSaveProgress){
autoSaveProgress();
autoSaveProgress = null;
}
autoSaveProgress = setTimeout(function() {
saveToLocalstorage('KEY', formData);
} ,1000); // 1s delay till commit
}

Related

Values in table on a .cshtml are not being updated after a post using ajax

I need to show information on a table in 2.cshtml that is on another 1.cshtml page called using #Html.Action("Action","Controller"), depending on the row selected on a table inside of 1.cshtml, the problem is that the information is not being refresh after the view returns.
When you select a row in table (1.cshtml) javascript gives me the value of the cell that i need from that row, after that i do a ajax post to my controller and it access it succesfully then my controller returns the view and access my 2.cshtml with the table, then it runs in my for to display the information, but the problem is that my 2.cshtml never reloads so the rows of my table are never updated.
Code for posting to controller
function submitForm(row) {
var idTool = el('idTool').value = row.cells[0].innerHTML;
var url_ = '../Tools/ToolTable';
jQuery.ajax({
type: "POST",
url: url_,
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ idToolPost:idTool })
});
}
Controller
[HttpPost]
public ActionResult ToolTable(int idToolPost)
{
var entitieTool = new Models.ToolControlEntities2();
List<Models.Tool> t = entitieTool.Tools.ToList();
List<Models.Equip> eqp = entitieTool.Equips.Include(x => x.Equip_Tool).ToList();
List<Models.Equip_Tool> eqpt = entitieTool.Equip_Tool.Include(x => x.Equip).Where(x => x.id_Tool == idToolPost).ToList();
ToolEquip ttteqpceteqptflt = new ToolEquip(eqpt, t, eqp);
ViewBag.SuccessMessage = "The information was succesfuly displayed.";
return View(ttteqpceteqptflt);
}
Table to show result
<table>
<div>
<thead>
<tr>
<th> Tool</th>
<th> Equip</th>
<th> Active</th>
</tr>
</thead>
</div>
<tbody>
#for (int x = 0; x < Model.eqtool_.Count; x++)
{
<tr>
<td style="display: none"><input id="idEquip" name="eq[#x].id_Equip" type="hidden" value="#Model.eqtool_[x].id_Equip" /></td>
<td style="display: none"><input id="idEquip" name="eq[#x].id_Tool" type="hidden" value="#Model.eqtool_[x].id_Tool" /></td>
<td>#Model.eqtool_[x].Tool.Tool_Name</td>
<td>#Model.eqtool_[x].Equip.Equip_Name</td>
<td>#Html.CheckBox("#Model.eqtool_[x].active")</td>
</tr>
}
</tbody>
</table>
After it runs my for the page dosen't show the new information, here is where i think i'm missing a refresh somewhere.
So I resolve my issue I just used the following:
the table was saved on my "texto" variable, and then I just replace the tbody (the information that i need) with the next line
document.getElementById('tooltabletbody').innerHTML = texto;

Angular it taking the old parameter when clicking button

I am trying to add a button which when clicked, calls a function which takes a parameter and sends it to my server. So far it looks like this:
<table class="table table-hover">
<thead>
<tr>
<th>Id</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="interview in $ctrl.pendingInterviews">
<td>{{ interview.id }}</td>
<td><input type="submit" name="Submit" id="submit" ng-click="$ctrl.addParticipant();"></td>
</tr>
</tbody>
</table>
What I have in my angular component:
var participant={
username:"mama",
interviewId:$routeParams.interviewId
};
console.log(participant);
console.log(JSON.stringify(participant));
this.addParticipant = function saveParticipant() {
console.log("in partikip")
Interview.addParticipant(JSON.stringify(participant))
.then(
function (errResponse) {
console.error('Error while fetching pending interviews');
}
);
}
And what I have in my angular service:
function addParticipant(participant) {
console.log("Im here too");
console.log(participant + "asdasdsda");
var deferred = $q.defer();
$http.post('http://localhost:8080/interviewsupdateparticipant', participant)
.then(
function (response) {
deferred.resolve(response.data);
},
function (errResponse) {
console.error('Error while adding participant');
console.error(''+ participant.username + participant.interviewId)
deferred.reject(errResponse);
}
);
return deferred.promise;
}
The problem is that first when I go to my page, participant from the controller has the username set to mama and the interviewId set to undefined. When I click the submit button, instead of sending the id and the hardcoded username, it sends undefined and the hardcoded username. Why? Why doesn't it automatically get the interviewId?
The moment I click Submit, the id stays undefined for some reason and it only changes if I click again. Any ideas what the problem could be?
Many things that could solve this:
Try using ngHref instead of just href when you have variable part of your url
Try passing the interview.id as a parameter to your addParticipant() method instead of getting it via the $routeParams variable
You have an input type="submit" outside any form, and inside an <a> link, try changing that

How to Ajax POST after a Form Submit

I think this is pretty simple but I cannot find anywhere how to do this, as the title says, how do you do an ajax post after a successful submit form post. I tried to search for it but all I see is the reverse of what I need which is submit after an ajax post. I'll try to make a draft of a program very similar to what Im working on.
This is my form.
<h2>My Form </h2>
#using (Html.BeginForm(new { #class = "submitForm" }))
{
<label>Loan Amount</label>
#Html.DropDownListFor(model => model.Loan.LoanAmount, Model.DropDownOfLoanAmount, new { #class = "LoanAmount", #data_bind = "value: selectedLoanAmount" })
#Html.ValidationMessageFor(model => model.Loan.LoanAmount)
<label>Loan Receivable</label>
#Html.TextBoxFor(model => model.Loan.LoanReceivable, "{0:0,0.00}", new { #class = "LoanReceivable", #readonly = true, dir = "rtl", #data_bind = "value: loanReceivable" })
#Html.ValidationMessageFor(model => model.Loan.LoanReceivable)
<label>Interest</label>
#Html.TextBoxFor(model => model.Loan.Interest, "{0:0,0.00}", new { #readonly = true, #class = "Interest", dir = "rtl", #data_bind = "value: interest" })
<table class="input-group">
<tbody data-bind="foreach: loanDeductions">
<tr>
<td><strong data-bind='text: deductionName'></strong></td>
<td>
<input class="deductionCode form-control" data-bind='value: amount, valueUpdate: "afterkeydown"' /></td>
<td><a href='#' data-bind='click: $parent.removeLine'>Delete</a></td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-danger">Save Deduction</button>
<button type="submit" class="btn btn-primary">Save changes</button>
}
This is an example ajax post (dont mind the logic of the post):
$.ajax({
'url' :'#Url.Action("UpdateDeductionValues","LoanApp")',
'data': {amount : $('.LoanAmount').val()},
'success': function(result) {
$.each(result, function (idx, items) {
$('.' + items.Code + '').val(items.Amount.toFixed(2));
});
}});
Now what I want to happen is when I submit that form, if the submit is successful, the ajax post is triggered. So its like posting 2 times in one button, the difference is that the other one is a form submit while the other is an ajax post. PLS help.
What you should do is "take over the submit button" with your jQuery, and then use an ajax call inside.
For example having this submit button:
<input type="submit" value="Submit" onsubmit="$('#your-form-id-here').submit()">
And having this jQuery submit function with an ajax call, should give you a pretty good idea on what to do.
$('#your-form-id-here').submit(function (e) {
e.preventDefault();
var senddata = $(this).serializeArray();
var sendto = $(this).attr("action");
$.ajax({
url: sendto,
type: 'POST',
data: senddata,
success: function (data) {
$('.messages').html(data);
},
error: function (error) {
$('.messages').html(error);
}
});
});
This basically takes your normal form, and send it through your ajax call, to your normal form action, so basically it works just like normal, but you now have the opportunity to do stuff in your form action php file, and also in your ajax success data. For example you could use this to deliver validation messages directly to your user, without refreshing your site. And so on...
i'm not sure what you are trying to do, what the point of doing ajax request after submitting the form the page will reload anyway.
however if need need do the ajax request after the submitting the form you just need an ajax call. but that that will work on every time when page load.
what i think you need to do make two ajax request the first one is for the submitting the form and if the call is successful then call the second request.

Reloading using Angular

Hello friends from SO!
I'm new into angular, and I'm trying to keep a table always updated with the information comming from a PHP webservice.
I'm demanding the information the first time using the following:
HTML
<div class="block" ng-controller="demandar_informacion" ng-init="visualizacion_masiva()">
<h1 class="block_header">Welcome admin</h1>
<p class="block_info"></p>
<table>
<thead>
<tr>
<th ng-repeat="header in headers ">{{header}}</th>
</tr>
</thead>
<tr ng-repeat="disponible in disponibles">
<td ng-repeat="(variable, valor) in disponible">{{valor}}</td>
</tr>
</table>
</div>
Then I'm using the following code to get the information:
Js Angular:
function demandar_informacion($scope, $http) {
//pedido de visualización masiva
$scope.visualizacion_masiva = function() {
var address = "http://127.0.0.1/usa/_code/index_records.php"
+ "?ac=view_all"
var pedido = $http({
method: 'GET',
url: address
})
.success(function(data, status) {
$scope.errors = data.error;
$scope.headers = data.headers;
$scope.disponibles = data.disponibles;
$scope.eliminados = data.eliminados;
$scope.info = data.info;
});
};
}
Main Q:
Is there any way I could re-send the HTTP packet and update the information every, let's say, 3 or 5 seconds? as It's rapidly changing.
Auxiliary:
At the same time, this fragment of code, seems to be altering the order of the values I have on the array, or it might be previously altered somewhere in the Angular code. I've checked the PHP and the Json string seems to be in right conditions, but when it comes to printing the values, it completely looses it's native order (shows the elements in an improper / unknown order)... anyone has a clue?
<tr ng-repeat="disponible in disponibles">
<td ng-repeat="(variable, valor) in disponible">{{valor}}</td>
</tr>
Thanks in advance!
Chris C. Russo
Update
$scope.update = function() {
$timeout(function() {
$http.get('lol').success(function() {
$scope.update();
});
}, 5000);
};
Old
Simplest way to do this:
$interval(function() {
demandar_informacion();
}, 5000);
buuuuutttt as MichaL pointed out in the comments what will happen is that 5 seconds will get eaten up as it becomes 5, 4, 3, 2, 1, DDOSing yourself due to the time it takes to complete the request.
Other ways:
Use firebase to wait and call the load function.
Long poll your php script.
You can use the $timeout service to call the server every few seconds. Or use websockets to push the changes from the server to your Angular app (with Ratchet, perhaps (http://socketo.me/))

Durandal. Pass additional data to other view

I've got a view that needs to be populated conditionally.
Scenario:
A manager will select a users name on screen B, then will be navigated to the same form the user filled in EG. screen A, except that the said manager will have the option to approve or deny the request of the user.
I've seen that in my VM on screen A I can do the following.
var vm = {
activate: function (data) {
console.log(data);
var id = data.id || -1;
if (id !== -1) {
router.isNavigating(true);
http.json('/api/user/'+ id )
.done(function (response) {
ko.viewmodel.updateFromModel(vm.userInfo, response);
router.isNavigating(false);
});
}
}
};
And then B (view & view model)
view
<table>
<thead>
<tr>
<td>User</td>
<td>Date Requested</td>
<td>Action</td>
</tr>
</thead>
<tbody>
<tr>
<td>Mike</td>
<td>19 Jun 2013
</td>
<td>
<input type="button" value="Go" data-bind="click: function() { buttons.goTo(6) }" />
</td>
</tr>
</tbody>
</table>
viewmodel
define(['durandal/plugins/router'], function (router) {
var buttons = {
goTo: function (id) {
console.log('goTo clicked');
//this does work in conjunction with my code on B
router.navigateTo('#/userinfo?id=' + id);
}
};
var vm = {
buttons: buttons
};
return vm;
});
My issue is that I'm not sure what the best way/or how to for that matter to get Durandal to navigate to page A from B... Is what I'm doing right? As it feels a little bit "hacky"
The navigation, at least to me, is designed to mimic standard MVC web navigation. In this case, since you already know that you want to go to 6, why not use an anchor like so
<a href="#/userinfo?id=6"/>
A better way would be to register your route with an id splat like so your route would become
routes.map({route: 'userinfo/:id, ...
<a href="#/userinfo/6" />
This way you can access the splat on the activate method..there are several examples out there but I don't have links to them. Basically the activate method of your userinfo viewmodel will accept a parameter and from there you can load an entity or whatever you like. Hope this helps.
Brad

Categories

Resources