Why does my button click execute multiple times? - javascript

I have written this ajax code to send data to web service asmx. It works but with a single click, it inserts data multiple times and sometimes it takes 2,3 click to insert data.
.js
<script type="text/javascript">
function save()
{
$("button").click
(
function()
{
$.post
(
"http://localhost:82/ws/himher.asmx/InsertUsers",
{name: txtUserName.value, pwd: txtUserPwd.value},
//
);
}
);
}
</script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<label>User Name</label>
<input id="txtUserName" type="text" class="form-control" />
</div>
</div>
<div class="row">
<div class="col-md-12">
<label>Password</label>
<input id="txtUserPwd" type="text" class="form-control" />
</div>
</div>
<br/>
<div class="row">
<div class="col-md-12">
<button type="submit" onclick='save()' class="btn btn-primary pull-right">Register</button>
</div>
</div>
</div>
.cs:
public class himher : System.Web.Services.WebService
{
[WebMethod(EnableSession = true)]
//[ScriptMethod(UseHttpGet = false)]
public string InsertUsers(string name, string pwd)
{
try
{
basicoperation bop = new basicoperation();
return bop.insertUsers(name, pwd);
}
catch (Exception ex)
{
throw ex;
}
}
public string insertUsers(string Name, string Password)
{
string status;
String ConStr = ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
SqlConnection sqlCon = new SqlConnection(ConStr); // to make a connection with DB
SqlCommand sqlCom = new SqlCommand("InsertUsers", sqlCon); // now in order to perform action such as insert SP, we must create command object which needs command name and conncetion only
sqlCom.CommandType = CommandType.StoredProcedure; // you must tell the system that insertInfo is a storedprocedure
SqlParameter sqlParamName = new SqlParameter("#UserName", Name);
SqlParameter sqlParamPwd= new SqlParameter("#Password", Password);
sqlCom.Parameters.Add(sqlParamName);
sqlCom.Parameters.Add(sqlParamPwd);
try
{
sqlCon.Open();
int i= sqlCom.ExecuteNonQuery(); // executenonquery is used for INSERT, UPDATE, DELETE
//sqlCom.ExecuteScalar(); // used to pick or read a single value from procedure
// Response.Write("Done");
sqlCon.Close();
status= "Success";
}
catch (Exception ex)
{
//response.Write(ex.Message);
status = ex.Message;
}
return status;
}
}

You have two bindings to a saving function, one of them is binded when you click on your button. Rewrite your JS like this:
<script type="text/javascript">
function save()
{
$.post(
"http://localhost:82/ws/himher.asmx/InsertUsers",
{name: txtUserName.value, pwd: txtUserPwd.value}
);
}
</script>
This way your save function will do only saving logic. Binding to call this function is done in HTML by <button type="submit" onclick='save()'>.

If you're going to release this code to users you really need to implement some duplicate action prevention rather than hope they just click it once. Ergo while you may find out why it insets multiples, you cannot rely on user behaviour to keep trash out of the database; they will hit a go slow and hammer that button in frustration. Even if you disable the button, they'll refresh and submit again. Dedupe your data before you insert - this is multi layer information security; even if they disable the script that stops them hammering the button, you don't accept the duplicates
Note, I don't offer this as a solution to a genuine "I click this once and 3 data are inserted" - fix that bug sure, but control the user behaviour with regards to your desire for data purity, within the server (where you're in total control)

Related

How to make bootstrap alert popup in another page when clicking on a button

Im trying to make an admin page where if i click on the button 'send', the message will be sent and there will popup a bootstrap alert on the employee page.
I have already the bootstrap alert setup, the message for the first time is shown. After I close and i send a message again i dont see any alert. I think it needs to be triggered when i click on the send button but im struggling about how to do that. Hope anyone can show me a simple way.
Here is the code for the admin page to send:
<form action="" method="post">
<fieldset>
<tr>
<div class="form-group">
<td>Send message</td>
<input type="text" id="msg" name="Bericht"/>
</div>
<div class="form group">
<button type="submit" id="sendButton" asp-page-handler="Submit" >Send</button>
</div>
</tr>
</fieldset>
</form>
And here is the code for the employeepage where there should be a popup bootstrap alert from the admin page
<script src="~/lib/signalr.js"></script>
<script type="text/javascript">
// Start the connection.
var connection = new signalR.HubConnectionBuilder()
.withUrl('/speedalarmhub')
.build();
connection.on('ReceiveMessage', function (message) {
var encodedMsg = message;
// Add the message to the page.
document.getElementById("output").innerHTML = encodedMsg;
});
// Transport fallback functionality is now built into start.
connection.start()
.then(function () {
console.log('connection started');
connection.invoke('SendMessage');
})
.catch(error => {
console.error(error.message);
});
</script>
<div class=container>
<div class="alert alert-warning">
×
<p id="output"></p>
</div>
</div>
And here is the code for the Submit handler
public void OnPostSubmit(NotificationModel notif)
{
DateTime datenow = DateTime.Now;
CreateNotification(datenow, notif.Bericht);
}
public void CreateNotification(DateTime convdayid, string Bericht)
{
var cs = Database.Database.Connector();
using var con = new NpgsqlConnection(cs);
con.Open();
var sql = "INSERT INTO notification(bericht, datumnu) VALUES(#Msg, #Date)";
using var cmd = new NpgsqlCommand(sql, con);
cmd.Parameters.AddWithValue("Msg", Bericht);
cmd.Parameters.AddWithValue("Date", convdayid);
cmd.Prepare();
cmd.ExecuteNonQuery();
con.Close();
}
Im trying to make an admin page where if i click on the button 'send', the message will be sent and there will popup a bootstrap alert on the employee page.
To achieve your requirement of pushing notification to all connected users (employees) and then update client UI with received data, you can refer to the following code snippet to modify your project.
inject an instance of IHubContext into admin page model class by adding it to your constructor
private readonly IHubContext<ChatHub> _hubContext;
public AdminPanelModel(IHubContext<ChatHub> hubContext)
{
_hubContext = hubContext;
}
update CreateNotification method to push notification to connected clients
public async Task CreateNotification(DateTime convdayid, string Bericht)
{
//...
//your code logic here
//...
await _hubContext.Clients.All.SendAsync("ReceiveMessage", $"{Bericht}");
Test Result
Note: for more information about "Send messages from outside a hub", please check this doc: https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-5.0

Prevent javascript firing on load page

I have MVC application with JavaScript in the body of the cshtml page. In Model, I have a method that returns a string, and I want that string to add in some div on a page on click of a button. It works, but, the method is triggered every time I load the page (and I want it to be triggered only on click.
Here is code:
Model:
public class TestJS
{
public string Tekst1 { get; set; }
public string Tekst2 { get; set; }
public TestJS()
{
Tekst1 = "one";
Tekst2 = "two";
}
public string AddTekst()
{
return "three (additional text from method)";
}
}
Controller:
public class TestJSController : Controller
{
// GET: TestJS
public ActionResult Index()
{
Models.TestJS tjs = new Models.TestJS();
return View(tjs);
}
}
View:
#model TestJavaScript.Models.TestJS
#{
ViewBag.Title = "Index";
}
<script type="text/javascript">
function faddtekst() {
whr = document.getElementById("div3");
var t = '#Model.AddTekst()';
whr.innerHTML += t;
}
</script>
<h2>Testing JavaScript Firing</h2>
<p>
First to fields:
#Model.Tekst1;
<br />
#Model.Tekst2;
</p>
<form>
<input type="button" value="Click to show Tekst3" onclick="faddtekst()" />
</form>
<br />
<hr />
<div id="div3">
</div>
I tried to wrap JS in $(document).ready() with same result.
Somebody may think of this as a strange approach, but, a model method that I'm trying to execute takes over 10 seconds in real code, so, I want to prevent waiting every time page loads (waiting should be only if the user clicks button).
The strangest thing is that Model.AddTekst() is executed EVEN if I comment it in javascript function with '//'.
Anyone knows how to avoid unwanted execution of Model.Method?
The behavior you are experiencing is not strange at all. #Model.AddText() executes on the backend once the view is compiled which is normal behaviour.
A comment in razor would look like this
#* Comment goes here *#
But this is not what you want to achieve.
I'm afraid your approach wont work since you can't execute a method on a model asynchronously.
I suggest you take a look at Ajax.BeginForm - more info here
You could implement a controller action on the backend which would return the text you want to display on the submitting of the form.
Try to use e.preventDefault() for button click.
<form>
<input type="button" value="Click to show Tekst3" id="Show" />
</form>
Try with jQuery
$(document).on("click", "#Show", function (e) {
e.preventDefault();
faddtekst();
});

Use MVC Session to store Client-side values (e.g. filter text) between visits

In an MVC View, is there an efficient way to store client-side values for use on subsequent page visits?
Typical scenario
An Index page has a table that's getting a bit long so I add a filter (I know paging is another option) and use an input control with some JavaScript to limit the table rows without having to perform another "Get" from the server.
This works fine but, if I navigate off (say) into an edit page then return back to the Index page, the filter is clearly no longer there.
After a bit of searching I never found anything simple so I post my meagre answer below.
The View contains a form at the top of the page into which a user can type filter text (on form "Get", text is set from a session value):-
<form id="frmEdit">
#Html.AntiForgeryToken()
<div class="form-group row">
<div class="col-sm-6">
#Html.ActionLink("Create New", "Create", null, new { #class = "nav-item nav-link" })
</div>
<label for="search" class="col-sm-2 col-form-label text-right">Filter</label>
<div class="col-sm-4">
<input type="text" placeholder="Filter" class="form-control" id="search" value=#Session["SparesSectionFilter"]>
</div>
</div>
</form>
A script section contains the filtering JavaScript but also a postback to the controller
#section Scripts{
<script type="text/javascript">
// on load
PerformFilter();
// hook up events
$(function () {
$("input#search").on("keydown keyup", function () {
PerformFilter();
// post back to session for reuse
$.post('SparesSections/Session_Add', { __RequestVerificationToken: $('[name=__RequestVerificationToken]').val(), itemName: 'SparesSectionFilter', itemValue: $("#search").val() });
});
})
</script>
}
I have a custom base-class for my controller into which I've added the following actions. These are usable from any controller using this class. The Razor view loads the session value but I've included a "Get" in the controller for client-side options.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Session_Add(string itemName, string itemValue)
{
Session.Add(itemName, itemValue);
return Json(new { itemName = itemName, itemValue = itemValue }, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult Session_Get(string itemName)
{
return Json(new { itemName = itemName, itemValue = Session[itemName] ?? string.Empty }, JsonRequestBehavior.AllowGet);
}

C# MVC5 JsonResult

I am trying to check for whether or not a CustomUrl is taken within my application. The problem is that when I click the submit button, nothing happens. I having a very difficult time understanding what I have done wrong.
To clarify: There is no javascript errors, the page does not get submitted. There are no errors anywhere of any sort for me to go on. Also, if I remove [Remote] section from AccountViewModel, so it does not attempt to make the check, the page will submit and it will also record the value in the database. So I'm fairly certain it has something to do with the validation I tried to put in place.
Here is the code:
MembersController.cs
public JsonResult IsCustomUrlInUse(string customUrl)
{
return Json(!UserManager.Users.Any(x => x.CustomUrl == customUrl), JsonRequestBehavior.AllowGet);
}
AccountViewModel.cs
[Required]
[StringLength(20, MinimumLength = 3)]
[Display(Name = "Custom URL")]
[Remote("IsCustomUrlInUse", "Members", ErrorMessage="Custom Url is already in use. Please choose another.")]
public string CustomUrl { get; set; }
Register.cshtml
#model Azularis.System.Events.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
<h2>#ViewBag.Title.</h2>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
#using (Html.BeginForm("Register", "Members", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.CustomUrl, new { #class = "col-md-2 control-label"})
<div class="col-md-10">
#Html.TextBoxFor(m => m.CustomUrl, new { #class = "form-control"})
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
EDIT:
Answering questions in comments:
Network Tab in Developer options is capturing the entry of Custom URL field.
When I remove Remote, the validation for minimum characters kicks in and displays an error. Also, even while Remote is there, the minimum character limit still kicks in.
Example of the network tab: http://postimg.org/image/8e2e1hesx/
I have also removed the bundle in the view, to make sure this is not happening due to duplication, but still the same thing happens.
EDIT 2:
I added a Logging line in the IsCustomUrlInUse method, but it never gets triggered. Can it be that somehow I need to enable json call to the server? As in the MVC is blocking json calls until I enable it in settings somewhere?
EDIT 3:
I managed to produce this error, I'm not sure how as I am not able to replicate it, but maybe this helps:
2015-11-29 13:50:19.4659||System.Web.HttpException (0x80004005): The controller for path '/__browserLink/requestData/c244808430ad49a5afee6a0ecb685cf7' was not found or does not implement IController.
at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)
at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
2015-11-29 13:50:47.0584||System.Web.HttpException (0x80004005): The controller for path '/__browserLink/requestData/c244808430ad49a5afee6a0ecb685cf7' was not found or does not implement IController.
at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)
at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Accessing Post method from View through JavaScript

I am facing problems accessing the ActionResult [Post] from my View.
View:
#using (Html.BeginForm()){
<form id="edit-order-form" action="#Href("~/Orders/Edit")">///EDIT:
....
<div class="row">
<span class="label"><label for="ShipPostalCode">PostalCode:</label></span>
<input type="text" id="txtShipPostalCode" name="ShipPostalCode" value="#ViewBag.ShipPostalCode" />
</div>
<div class="row">
<span class="label"> </span>
<input type="submit" id="btnSave" name="submit" value="Save" />
</div>
</fieldset>
</form>
<script type="text/javascript">
$("#btnSave").live("click", saveRecord);
function saveRecord() {
$.ajax(
{ type: "Post" ,
url: '#Url.Action("Save", "OrdersList")',
data: {
OrderID: $("#hdnOrderID").val(),
ShipName: $("#txtShipName").val(),
ShipAddress: $("#ShipAddress").val(),
RequiredDate: $("#RequiredDate").val(),
ShipPostalCode: $("#ShipPostalCode").val(),
},
dataType: "html" ,
success: function (data){
alert ('saved');
}
}).....
Controller:
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Save(int orderId = 0, string ShipName = "", string ShipAddress = "", string ShipPostalCode = "", DateTime? RequiredDate = null)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);
using (SqlCommand cmd = new SqlCommand("GetOrders", conn))
{
conn.Open();
//SqlCommand cmd = new SqlCommand( "GetOrders", "connection string");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ID", orderId);
cmd.Parameters.AddWithValue("#ShipName", ShipName);
cmd.Parameters.AddWithValue("#ShipAddress", ShipAddress);
SqlParameter paramDate = cmd.Parameters.Add("#RequiredDate",
System.Data.SqlDbType.DateTime);
paramDate.Value = RequiredDate;
//cmd.Parameters.AddWithValue("#RequiredDate", RequiredDate);
cmd.Parameters.AddWithValue("#ShipPostalCode", ShipPostalCode);
//SqlParameter Total = cmd.Parameters.Add("#Total", SqlDbType.Int);
//Total.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
conn.Close();
return View();
}
}
The controller action doesn't get called. Probably the javascript function neither.
First what you need to do is change the 'type' attribute of the 'btnSave' input element to 'button' so it doesn't post the page when clicked. 'Input' elements with the type of 'submit' will actually post the page, which is not what you want when you want to execute javascript when a button is clicked.
Next what you'll need to do is use either IE or Chrome and pull up the Developer tools, 'F12'. In Chrome, click the 'Sources' tab, then open the 'Navigator' by clicking the 'boxed arrow' below the 'Elements' tab. Find the file which holds your javascript and breakpoint the line which has the following syntax, $.ajax(. Then go to your page and click the 'Submit' button. From there, you should see exceptions that are most likely causing your javascript to fail.
Also, you may want to open 'Fiddler' and watch to see if the 'Post' to your RESTful service is kicking off.
Have you tried using document.forms[0].submit(); instead? To see if it's a problem with the posting or your javascript?
Also .live is deprecated, you should be using .on instead.
example code:
$("#btnSave").on("click", saveRecord);
//or $("#btnSave").click( function(){
// document.forms[0].submit();
//});
function saveRecord() {
document.forms[0].submit();
})
And change your Save action result's attributes to [HttpPost] and below that [ActionName("Edit")]

Categories