I have the following script which is rendering a partial view inside a dialog box:
$(function () {
$('#addressLookupBtn').click(function () {
$('#dialog').dialog({
title: 'Address Lookup Tool',
modal: true,
width: '1200',
height: 'auto',
resizable: false,
show: {
effect: "fade",
duration: 2000
},
hide: {
effect: "fade",
duration: 1000
},
open: function (event, ui) {
//Load the AddressLookup action which will return
//the partial view: _AddressLookup
$(this).load("#Url.Action("AddressLookup", new { evpId = Model.EvpId })");
}
}).dialog('open');
});
});
The problem is, when I submit the partial view, there are 2 POSTS being made to the server, I think the submit for the partial view is also being bound to the $('#addressLookupBtn').click. Can anyone see where I'm going wrong?
more info
Partial view
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "updatearea" }))
{
<div id="updatearea" class="form-group">
<div style="width:300px; display:block; float:left;">
#Html.TextBox("PostCode", null, new { #class = "form-control" })
</div>
<div id="NewAddressLine">
<input type="submit" value="Lookup Postcode" class="btn btn-default" />
</div>
</div>
}
It looks like the post is being submitted using both a normal form submit and as a jquery event.
Perhaps change it to a button (instead of submit) and use only the jquery submit, or remove the jquery event and use only the normal form submit.
As per comments - An example of using jquery ajax instead of MS ajax:
The script:
$(document).ready(function() {
event.preventDefault(); // stop the form from submitting the normal way
$('#MyForm').submit(function(event) {
$.post(
$('#MyForm').attr('action'),
{ 'PostCode' : $('input[name=PostCode]').val() }
)
.done(function(data) {
alert('Post worked, and data was returned. Parse and/or present.');
$('#updatearea').html(data); //Replace the current contents of "updatearea" with the returned contents
});
});
});
The PartialView:
#using (Html.BeginForm("MyAction", "MyController", new { #id = "MyForm" }))
{
<div id="updatearea" class="form-group">
<div style="width:300px; display:block; float:left;">
#Html.TextBox("PostCode", null, new { #class = "form-control" })
</div>
<div id="NewAddressLine">
<input type="submit" value="Lookup Postcode" class="btn btn-default" />
</div>
</div>
}
It looks like you are calling open, and still have autoOpen set to true (it is true by default). This is causing open event to run twice. Try setting autoOpen to false
$('#dialog').dialog({
...
autoOpen: false,
...
});
https://api.jqueryui.com/dialog/#option-autoOpen
It turns out I didn't need to change anything other than move the following bundle reference from _Layout to my Edit view:
#Scripts.Render("~/bundles/unobtrusive-ajax")
Related
I have a strange problem that's really starting to bug me. Apologies in advance for a wall of code and somewhat confusing question.
I need to display a modal form for the user, and have them fill in some details.
The user can click Save to save their changes.
The user can click Cancel to cancel their changes.
I use the save handler to serialize the form and send its data to a JSON service.
If I have a form with multiple input fields, it all works great, and nothing unexpected happens.
If I have a form with a single input field, however, I get an unexpected side-effect. Hitting Enter/Return in that input field causes the modal form to be submitted, and instead of my JSON handler getting called the page is reload with the form's arguments as parameters — exactly as if the form is being submitted. In fact, adding an action= parameter to the form element has proven that, as you get navigated to the page you specify.
Here's the form I'm using:
<form id="surveyQuestionForm" class="form-horizontal" style="display:none;">
<div class="row">
<input name="surveyQuestionId" id="surveyQuestionId" type="hidden">
<input name="surveyId" type="hidden" value="${survey.surveyId}">
<div class="control-group">
<label class="control-label" for="questionType"><b><spring:message code="survey.question.type"/></b></label>
<div class="controls">
<select class="input-large" name="questionType" id="questionType">
<option value="">(Select one)</option>
<c:forEach items="${surveyQuestionTypes}" var="surveyQuestionType">
<option value="${surveyQuestionType.code}">${surveyQuestionType.name}</option>
</c:forEach>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="questionText"><b><spring:message code="survey.question.text"/></b></label>
<div class="controls">
<input type="text" class="input-xlarge" name="questionText" id="questionText" maxLength="64"/>
</div>
</div>
</div>
</form>
and here's the code I use to display the form modally:
function addQuestion() {
// find the form, and initialise its validation.
var form = $('#surveyQuestionForm');
var validator = form.validate(
{
rules: {
questionType: {
required: true
},
questionText: {
required: true
}
},
messages: {
questionType: {
required: '<spring:message javaScriptEscape="true" code="survey.question.type.required"/>'
},
questionText: {
required: '<spring:message javaScriptEscape="true" code="survey.question.text.required"/>'
}
},
onkeyup: false
});
// reset form validation, and hide any error message
validator.resetForm();
$("#errorMessage").hide();
// show the dialog
bootbox.dialog({
title: '<i class="icon-plus green"/> <spring:message javaScriptEscape="true" code="survey.add.question"/>',
message: form,
closeButton: false,
buttons: {
cancel: {
label: '<i class="icon-remove bigger-130"></i> <spring:message javaScriptEscape="true" code="button.cancel"/>',
className: "btn btn-danger"
},
save: {
label: '<i class="icon-ok bigger-130"></i> <spring:message javaScriptEscape="true" code="button.save"/>',
className: 'btn btn-success',
callback: function () {
var result = false;
if (!form.valid())
return false;
$.ajax({
type: "POST",
url: '/addSurveyQuestion.json',
async: false,
data: form.serialize(),
success: function (outcome) {
if (outcome.success) {
$('#question-list').dataTable().fnReloadAjax();
result = true;
}
else {
$("#errorMessage").html(htmlEncode(outcome.message)).show();
}
}
}
).fail(function () {
$.gritter.add({
title: '<spring:message javaScriptEscape="true" code="general.error"/>',
text: '<spring:message javaScriptEscape="true" code="server.error"/>',
class_name: 'gritter-error'
}
);
}
);
return result;
}
}
},
show: false,
animate: false,
onEscape: false
}
).on('shown.bs.modal', function () {
var form = $('#surveyQuestionForm');
form.find('#surveyQuestionId').val(null);
form.find('#questionType').val('');
form.find('#questionText').val('');
form.show().find('#questionType').focus();
form.show();
}
).on('hide.bs.modal', function (e) {
if (e.target === this)
$('#surveyQuestionForm').hide().appendTo('body');
}
).modal('show').addClass("bootboxDialog40");
}
If I use this code as-is, with Bootbox 4.4, hitting Enter/Return while the user is in the questionText field submits the form, and my page redisplays but with the form fields as parameters, eg:
page.html?surveyQuestionId=&surveyId=3&questionType=Y&questionText=blah
If I have a second input field, hitting Enter/Return in the fields does nothing, and the user has to click Save or Cancel.
Submit-on-enter for a single input field is a browser behavior that you will need to override. You can do this a few ways.
<form onSubmit="return false;">
I don't think you are using the native submit function at all, so adding this bit of inline scripting prevents the form submission. But putting scripts in your markup isn't great. A little jQuery can do the same thing for you:
$('form').on('submit', function(){ return false; });
I believe this is not related to bootbox plugin. The actual reason is here:
https://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2
When there is only one single-line text input field in a form, the user agent should accept Enter in that field as a request to submit the form.
Coming to the solution, you can add another hidden field in your form which will prevent the submission of the form on enter.
I am trying to submit an ajax form that is loaded via a partial page. The submit comes from a button that is created on a JQuery UI Dialog. The form data is included in the request but when I step through the code on the server side the view model is not being populated with the data.
Javascript that loads the partial and after load is complete creates the dialog.
$('#test').load('#Url.Action("NewIntegrationLevel", "IntegrationLevelConfig", null, Request.Url.Scheme)',
function() {
var dialog = $('#addEditForm');
dialog.dialog({
resizable: false,
modal: true,
width: 500,
title: 'New Integration Level',
buttons: [{
text: 'Save',
click: function(e) {
e.preventDefault();
$('#addEditForm').submit();
dialog.dialog('close');
},
type: 'submit',
form: 'addEditForm'
},
{
text: 'Close',
click: function(e) {
e.preventDefault();
dialog.dialog('close');
}
}
]
});
});
My partial page:
#model Zodiac.Cmt.UI.Models.IntegrationLevelConfigViewModel
#using (Ajax.BeginForm("Save", "IntegrationLevelConfig", FormMethod.Post, null, new { id = "addEditForm" }))
{
<div id="addEdit-integration-dialog">
<div>
<div>
#Html.LabelFor(model => model.Name)
#Html.TextBoxFor(model => model.Name)
</div>
</div>
</div>
}
Server side code:
[HttpPost]
public ActionResult Save(IntegrationLevelConfigViewModel viewModel)
{
return PartialView("_AddEditIpl", viewModel);
}
Since the JQuery dialog creates the submit button outside the form I am using the "form" attribute on the button so that it knows which form to submit.
This is what the request looks like after submitting the page:
So, why doesn't the viewmodel get populated with the form data on the server side???
ViewModel:
public class IntegrationLevelConfigViewModel
{
[Description("Name")]
public string Name;
}
I figured it out.
In my view model
public string Name;
needs to change to:
public string Name {get;set;}
I have an ajax function on the initialize of the main router that seems to hinder the event of my signin button in signin.js. When I click the signin button, it doesn't perform its function, instead the browser places the inputs on the URL, (i.e. username and password).
But when I remove the ajax function on the initialize, I can successfully log in.
I've included some of the codes I'm working on. Thanks
main.js
initialize: function(){
$.ajax({
type: "GET",
url: "something here",
contentType: "application/json",
headers: {
'someVar': something here
},
statusCode: {
404: function() {
console.log('404: logged out');
if (!this.loginView) {
this.loginView = new LoginView();
}
$('.pagewrap').html(this.loginView.el);
},
200: function() {
console.log('200');
if (!this.homeView) {
this.homeView = new HomeView();
}
$('.pagewrap').html(this.homeView.el);
}
}
});
// return false;
},
signin.js
var SigninView = Backbone.View.extend ({
el: '#signin-container',
events: {
"click #btn-signin" : "submit"
},
submit: function () {
console.log('signin');
$.ajax({ ... });
return false;
}
});
var toSignin = new SigninView();
window.anotherSigninView = Backbone.View.extend({
initialize: function() {},
render: function() {}
});
home.js
window.HomeView = Backbone.View.extend ({
initialize: function() {
this.render();
},
render: function() {
$(this.el).html( this.template() );
return this;
}
});
some html
<form id="signin-container">
<table id="tbl-signin">
<tr>
<td><div class="input-box"><input class="input-text" type="text" name="username" placeholder="Username"></div></td>
<td><div class="input-box"><input class="input-text" type="password" name="password" placeholder="Password"></div></td>
<td><input id="btn-signin" class="button" value="Sign In"></td>
</tr>
<tr>
<td class="opt"><input class="checkbox" type="checkbox" name="rememberMe" value="true"><label class="opt-signin">Remember Me?</label></td>
<td class="opt"><a class="opt-signin" href="#">Forgot Password?</a></td>
<td></td>
</tr>
</table>
</form>
You need to prevent the default behaviour of the submit button in your click handler. You can do this like so:
var SigninView = Backbone.View.extend ({
el: '#signin-container',
events: {
"click #btn-signin" : "submit"
},
submit: function (event) {
event.preventDefault();
console.log('signin');
$.ajax({ ... });
}
});
Alternatively, you might consider using the html button element which won't attempt to submit the form it's associated with.
Ok, I figured out what's your problem :)
Here is an example that resumes your code jsfiddle.net/26xf4/6. The problem is that you don't call new SigninView(); (instantiate the view) hence its events are never bound.
So, in this example try to uncomment the ligne 43 and your code will work as expected, because when you instantiate a View (new SigninView()) its constructor calls the delegateEvents() function (you don't see this in your code, it's in the backbone.js) enabling the events you declare in your view :
events: {
"click #btn-signin" : "submit"
},
I don't know about your HTML mockup, my best guess is that you are catching the incorrect event here. If you are submitting a form, you should catch submit form event not click #some-button. Because even if you catch click event of button inside a form and return false, the form will be still submitted because those are 2 different events
I'm trying to submit an ajax form from my razor view, and I want the controller to return a JSON object. When I use ("#form0").submit(alert("hi");); the data goes to the controller and I get an alert. However, when I use ("#form0").submit(function(){alert("hi");}); the data does not get passed, and I do not get an alert. I get the feeling that this is something minor with my syntax that I'm missing. Here's the relevant code:
jquery:
$(function () {
//setting up the schedule modal dialoag.
$("#schedModal").dialog({
buttons: {
Submit:
function () {
$("#form0").ajaxSubmit(function () {
//this is where I want to put the magic, but I need the alert to fire first.
alert("hi");
return false;
});
},
Cancel:
function () {
$(this).dialog("close");
}
},
autoOpen: false,
minHeight: 350,
modal: true,
resizable: false
});
the targeted view:
#model FSDS.DataModels.Schedule
#using (Ajax.BeginForm("scheduleNew", null, new AjaxOptions { UpdateTargetId = "partial" }, new {}))
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.ScheduleName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ScheduleName)
#Html.ValidationMessageFor(model => model.ScheduleName)
</div>
#* tons of other labels and editor fields go in here, omitted for brevity. *#
}
The controller, if that matters:
[HttpPost]
public ActionResult scheduleNew(Schedule schedule)
{
if (Request.HttpMethod == "POST")
{
FSDSDBEntities context = new FSDSDBEntities();
if (ModelState.IsValid)
{
context.Schedules.AddObject(schedule);
context.SaveChanges();
}
return Json(schedule);
}
else
{
return PartialView();
}
}
Simply use $('#form0').submit();:
Submit: function () {
$('#form0').submit();
}
Then define an OnSuccess handler in your AjaxForm that will be invoked when the AJAX request succeeds:
#using (Ajax.BeginForm("scheduleNew", null, new AjaxOptions { OnSuccess = "success", UpdateTargetId = "partial" }, new {}))
and finally success javascript handler:
function success(data) {
// the form was successfully submitted using an AJAX call.
// here you could test whether the data parameter
// represents a JSON object or a partial view
if (data.ScheduleName) {
// the controller action returned the schedule JSON object
// => act accordingly
} else {
// the controller action returned a partial view
// => act accordingly
}
}
Here is my code:
<td class="tedit">
<%= Html.ActionLink(item.Comments, "Comments", new { jobNumber = item.JobNumber, ordNumber = item.OrderNumber }, new { #class = "modalEdit" })%>
</td>
<div id="resultEdit" title="Edit Comments" style="display: none;">
<% Html.RenderPartial("AddComments", Model.InnerModel.RoadReportModelProp); %>
</div>
<script type="text/javascript">
$(document).ready(function () {
//initialize the dialog
$("#resultEdit").dialog({ modal: true, width: 300, resizable: true, position: 'center', title: 'Add Comments', autoOpen: false,
buttons: { "Save": function () {
var dlg = $(this);
dlg.Close();
}}
});
});
$(function () {
$('.modalEdit').click(function () {
//load the content from this.href, then turn it into a dialog.
$('#resultEdit').load(this.href).dialog('open');
$.unblockUI();
return false;
});
});
</script>
I need to send a POST request to the controller when I click on the SAVE button in the dialog, but I am not able to send a POST.
Please help.
You should be able to use $.post to save your data. For example
$.post(url, data, function(response) {
// Do something with response
});
You will need to collect the data from the dialog.
Regards,
Huske
<div>
<% using (Html.BeginForm("Post-FormActionName", "Controllername"))
{
%>
<div class="fieldsColumn">
<label>Name: *</label>
<%=Html.TextBoxFor("Name")%>
</div>
<div class="fieldsColumn">
<input id="submit" type="submit" value="Save"/>
</div>
<%}%>
</div>
You can use the following to Post, further, can you provide the code for the form you want to post, & also the controller you have created:
<script type="text/javascript">
$(document).ready(function() {
//get the form
var f = $("#idofForm");
var action = f.attr("action");
var serializedForm = f.serialize();
$.post(action, serializedForm, function() {
alert('we are back');
}
});
</script>