I have a page to add outcomes to a areas on a form. I utilise Editor templates to group the outcomes into areas and allow the outcome to be selected from a drop down list. I'd like to show an optional comments box for two of the 3 possible outcomes.
The main page is the following:
#model DBS.ViewModels.OutcomeQuestionnaireVM
#{
ViewBag.Title = "Outcomes";
}
<h2>Add Outcomes</h2>
#if (Model.Error == true)
{
<h3 class="danger">You MUST select an outcome for at least 1 area.</h3>
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.HiddenFor(x => x.DebriefId)
<hr />
#Html.EditorFor(m => m.Groups, new { outcomes = Model.Outcomes })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Next" class="btn btn-default" />
</div>
</div>
</div>
}
The group editor template is:
#model DBS.ViewModels.OutcomeQuestionGroupVM
#{
Layout = null;
}
<h4>#Html.DisplayFor(m => m.Name)</h4>
#Html.EditorFor(m => m.Questions, new { outcomes = ViewData["outcomes"] })
The final editor template for the outcome is:
#model DBS.ViewModels.OutcomeQuestionVM
#{
Layout = null;
}
<div class="form-group">
<div class="row">
<div class="col-md-4">
#Html.DisplayFor(m => m.Question)
</div>
<div class="col-md-4">
#Html.HiddenFor(m => m.ID)
#Html.DropDownListFor(m => m.OutcomeId, (SelectList)ViewData["outcomes"], "Please Select if applicable", new { #class = "form-control", #id = "OutcomeId" })
#Html.ValidationMessageFor(m => m.OutcomeId, "", new { #class = "text-danger" })
</div>
<div class="col-md-4" id="Comments">
#Html.HiddenFor(m => m.Comments)
#Html.TextAreaFor(model => Model.Comments, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Comments, "", new { #class = "text- danger" })
</div>
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(document).ready(function ()
{
document.getElementById('Comments').hide;
});
$(function () {
$(".DropChange").change(function () {
var valone = $('#OutcomeId').val();
if (valone == 1 || valone == 2)
{
$('#Comments').show();
}
else if (valone == 3)
{
$('#Comments').hide();
}
else
{
$('#Comments').hide();
}
});
});
</script>
}
However javascript doesn't do anything.
Sections are not supported in partial views, which is fortunate in your case or you would be adding multiple inline copies of each script in the jqueryval bundle as well as your own script (one each time the template is added).
Your also generating invalid html because of the duplicate id attributes generated by new { id = "OutcomeId" } and <div class="col-md-4" id="Comments"> which means the script would never have worked anyway.
You are also generating a hidden input for Comments before the textarea for the same property, which means that when the form is submitted, the value of Comments will be the initial value (as generated by #Html.HiddenFor(m => m.Comments)) and the value of the <textarea> would be ignored.
Its the responsibility of the view to include the scripts, not the partial, so move the scripts to the main view (or layout) and use class names and relative selectors.
Your html in the template should be
<div class="row">
<div class="col-md-4">
#Html.DisplayFor(m => m.Question)
</div>
<div class="col-md-4">
#Html.HiddenFor(m => m.ID)
// add class name to handle the .change() event
#Html.DropDownListFor(m => m.OutcomeId, (SelectList)ViewData["outcomes"], "Please Select if applicable", new { #class = "form-control outcome" })
#Html.ValidationMessageFor(m => m.OutcomeId, "", new { #class = "text-danger" })
</div>
<div class="col-md-4" class="comments"> // use class name
#Html.TextAreaFor(model => Model.Comments, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Comments, "", new { #class = "text- danger" })
</div>
</div>
then include css to initially hide all comments
.comments {
display: none;
}
and the script in the main view
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(".outcome").change(function () {
var valone = $(this).val();
// get the associated comment
var comment = $(this).closest('.row').find('.comments');
if (valone == 1 || valone == 2) {
comment.show();
} else {
comment.hide();
}
});
</script>
}
Note it was not clear what $(".DropChange") was referring to but I assume its the dropdownlist in your template (which I gave class="outcome")
Related
My code looks like
<div class="col-4">#Html.LabelFor(m => m.Password)</div>
<div class="col-8">
#Html.EditorFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</div>
I am using Javascript in my application.
How to write onfoucsout/onblue event to my Password textbox?
You can try like below:
<div class="col-8">
#Html.EditorFor(m => m.Password, new { htmlAttributes = new { onblur = "OnBlurEvent()" } })
#Html.ValidationMessageFor(m => m.Password)
</div>
#section scripts{
<script type="text/javascript">
function OnBlurEvent() {
alert("Hello!");
}
</script>
}
Or use Anonymous Function
#section scripts{
<script type="text/javascript">
$('#Password').blur(function(){
alert("Hello!");
});
</script>
}
I have coded a edit modal, is does works, but when I dismiss the modal and try to open it a second time, it just goes dark.
My link calling the modal
#Html.ActionLink("Editar", "GetEditSv", "Sv", new { id = sv.IDServico },new{data_target = "#modal-container", data_toggle = "modal"})
my container inside the parent view
<div id="modal-container" class="modal fade hidden-print" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
</div>
</div>
a script to erase the modal data and the parent view (take on the internet)
<script>
$(function () {
//when the modal is closed
$('#modal-container').on('hidden.bs.modal', function () {
//remove the bs.modal data attribute from it
$(this).removeData('bs.modal');
//and empty the modal-content element
$('#modal-container .modal-content').empty();
});
});
$('#modal-container').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
var url = button.attr("href");
var modal = $(this);
//note that this will replace the content of modal-contant ever time the modal is opened
modal.find('.modal-content').load(url);
});
</script>
A part of the modal view (a separated file)
#model ControleIntegrado.Models.Servico
#using (Html.BeginForm("EditSv", "Sv", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Servico</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.IDServico)
<div class="form-group">
#Html.LabelFor(model => model.Data, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Data.Date, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Data, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Salvar" class="btn btn-default" />
<input type="button" class="btn btn-default" data-dismiss="modal" value="cancelar"/>
</div>
</div>
</div>
}
<script src="~/Scripts/bootstrap.js"></script>
<script src="~/Scripts/jquery-ui-1.12.1.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
and the action on the controller
public ActionResult GetEditSv(int id)
{
using(DBControle db = new DBControle())
{
foreach (var item in db.Servico)
{
if(item.IDServico == id)
{
return PartialView("GetEditSv", item);
}
}
}
return ViewBag();
}
https://i.stack.imgur.com/2y7NP.png
Try this, use $('body').find('.modal-backdrop').removeClass('modal-backdrop'); to remove the backdrop effect (dark background)
<script>
$(function () {
//when the modal is closed
$('#modal-container').on('hidden.bs.modal', function () {
//remove the bs.modal data attribute from it
$(this).removeData('bs.modal');
//and empty the modal-content element
$('#modal-container .modal-content').empty();
//remove backdrop
$('#modal-container').find('.modal-backdrop').removeClass('modal-backdrop');
});
});
$('#modal-container').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
var url = button.attr("href");
var modal = $(this);
//note that this will replace the content of modal-contant ever time the modal is opened
modal.find('.modal-content').load(url);
});
</script>
I am working on an asp.net mvc web application. on my main view i got the following create link:-
<a class="btn btn-success" data-modal="" href="/Staff/Create" id="btnCreate">
<span class="glyphicon glyphicon-plus"></span>
</a>
<!-- modal placeholder-->
<div id='myModal' class='modal fade in'>
<div class="modal-dialog">
<div class="modal-content">
<div id='myModalContent'></div>
</div>
</div>
</div>
and i have the following script:-
$(function () {
$.ajaxSetup({ cache: false });
$("a[data-modal]").on("click", function (e) {
$('#myModalContent').load(this.href, function () {
$('#myModal').modal({
keyboard: true
}, 'show');
$('#myModalContent').removeData("validator");
$('#myModalContent').removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse('#myModalContent');
bindForm(this);
});
return false;
});
});
function bindForm(dialog) {
$('#myModalContent', dialog).submit(function () {
if ($('#myModalContent').valid()) {
$('#progress').show();
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$('#myModal').modal('hide');
$('#progress').hide();
//location.reload();
alert('www');
} else {
$('#progress').hide();
$('#myModalContent').html(result);
bindForm();
}
}
});
}
else {
return false;
}
});
}
Now when i click on the Create link the Create action method that will return the following partial view, which will be rendered inside a modal popup :-
#model SkillManagement.Models.Staff
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Staff</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.GUID, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GUID)
#Html.ValidationMessageFor(model => model.GUID)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IsExternal, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.IsExternal)
#Html.ValidationMessageFor(model => model.IsExternal)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
</div>
//code goes here
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
till now i have every thing working well, the Get Create action method will be called and the partial view will be rendered inside a modal popup.
but now inside my partial view if i click on "Create" button , the Post create action method will be called but not due to the javascript code . and when i check Request.IsAjax() inside my Post create action method, i got that it is not an ajax request which means the partial view send a normal Post http and not ajax request as defined inside the script,, can anyone advice what is wrong in my current approach ?
Thanks
as you can see you just pass the #myModalContent node to the bindForm function, and jQuery selector looks for
// will never find #myModalContent
$('#myModalContent', myModalContentDOMElement).submit(function () {
Instead you should do something like this
$('form', dialog).submit(function (e) {
e.preventDefault(); // stop the default form submit action
You are loading your form into the page via ajax, but the form you are loading is a regular html form if you want the form itself to use ajax, I believe are looking for #Ajax.BeginForm().
msdn documentation
#using (Ajax.BeginForm({objectparams})){
...
I am working my way through a MVC 5 application, using Bootstrap modals. I have come across a bit of an inconsistency when trying to access a particular Partial page with modals from different web pages. One of the modals works fine, the other does not work at all.
(I have referenced Modals in MVC 5 when learning how to do this - so it's possible i'm making a boneheaded mistake somewhere, but I do not think so).
I'll start with the relevant code, then at the bottom I will go over what I have tried.
modalform.js (this was pretty much copy/pasted from the above reference object)
$(function () {
$.ajaxSetup({ cache: false });
$("a[data-modal]").on("click", function (e) {
// hide dropdown if any
$(e.target).closest('.btn-group').children('.dropdown-toggle').dropdown('toggle');
$('#myModalContent').load(this.href, function () {
$('#myModal').modal({
backdrop: 'static',
keyboard: true
}, 'show');
bindForm(this);
});
return false;
});
});
Modal Partial Page (Create)
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add New Site</h4>
</div>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="modal-body">
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.OrganisationSelected, htmlAttributes: new { #class = "control-label col-lg-3" })
<div class="col-md-10">
#Html.DropDownListFor(model => Model.OrganisationSelected, Model.Organisations, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.OrganisationSelected, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SiteName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SiteName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SiteName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SiteAbbr, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SiteAbbr, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SiteAbbr, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SiteNotes, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SiteNotes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SiteNotes, "", new { #class = "text-danger" })
</div>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal">Cancel</button>
<input class="btn btn-primary" type="submit" value="Save" />
</div>
</div>
</div>
}
AllSites.cshtml (This one works fine - and yes, I know about the for loop not being best practice.)
#model IEnumerable<DRPlanner.ViewModels.OrganisationSiteViewModel>
#using DRPlanner.Helpers
#{
ViewBag.Title = "All Sites";
}
<!-- modal placeholder-->
<div id='myModal' class='modal fade in'>
<div class="modal-dialog">
<div class="modal-content">
<div id='myModalContent'></div>
</div>
</div>
</div>
#for (int i = 0; i < Model.Count(); i++)
{
if ((i == 0) || (Model.ElementAt(i).OrgId != Model.ElementAt(i - 1).OrgId))
{
<strong>
#Html.RouteLink(Model.ElementAt(i).OrganisationName.ToString() + " (" + Model.ElementAt(i).OrganisationAbbr.ToString() + ")", "OrgShort", new { org = Model.ElementAt(i).OrgId })
</strong>
#:<ul class="list-unstyled">
}
if (Model.ElementAt(i).SiteName != "")
{
<li>
#Html.RouteLink(Model.ElementAt(i).SiteName.ToString(), "SiteShort", new { org = Model.ElementAt(i).OrgId, site = Model.ElementAt(i).SiteId })
</li>
}
if ((i == Model.Count() - 1) || (!Model.ElementAt(i).OrganisationAbbr.Equals(Model.ElementAt(i + 1).OrganisationAbbr)))
{
#:</ul>
}
}
<br />
#Html.RouteLink("New Organisation", "NewOrg", new { controller = "Organisation", action = "Create" })
#Html.RouteLink("New Site", "NewSite", new { controller = "Site", action = "Create" }, new { data_modal = "", id = "btnCreate", #class = "btn btn-small btn-primary" })
Sites.cshtml (This one doesn't work)
#model IEnumerable<DRPlanner.ViewModels.OrganisationSiteViewModel>
#{ViewBag.Title = "Sites";}
Sites For #ViewBag.OrganisationName
<ul class="list-unstyled">
#foreach (var item in Model)
{
<li>#Html.RouteLink(item.SiteName.ToString(), "SiteShort", new { site = item.SiteId })</li>
}
</ul>
#Html.ActionLink("Add Site", "Create", "Site", null, new { data_modal = "", id = "btnCreate", #class = "btn btn-small btn-primary" })
<script src="~/Scripts/modalform.js"></script>
<!-- modal placeholder-->
<div id='myModal' class='modal fade in'>
<div class="modal-dialog">
<div class="modal-content">
<div id='myModalContent'></div>
</div>
</div>
</div>
What I have done:
I have debugged the running of the modalform.js in the VS2013 debugger, and found that when it is run from the AllSites.cshtml, the $('#myModal').modal is referring to a function (I have no clue how or where this function is pulled from, sorry), but when it is run on the Site.cshtml, $('#myModal').modal is undefined. So I know that is where the error is: i'm just clueless as to how to resolve the issue (or perhaps just clueless in general). One other piece of information: Sites.cshtml and AllSites.cshtml are both actions of DIFFERENT controllers to where the Create action exists. Basically, I am trying to get the modal to be accessible from multiple locations within the site. Any help is greatly appreciated (I don't have 15 rep yet, so upvotes will need to be pro-rata'ed for later).
The Error: 0x800a01b6 - JavaScript runtime error: Object doesn't support property or method 'modal'
Ok, I found the problem.
The _Create.cshtml class had some unnecessary javascript and css files being referenced/loaded up. It seems that one (or more) of these was causing a conflict, which (naturally) disappeared once I commented/removed these unnecessary references.
Thanks all for your time and efforts. Issue is now resolved!
We have the following code for registration page
#using (Html.BeginForm(MVC.Account.Register(Model.ReturnUrl), FormMethod.Post, new { #id = "register-form" }))
{
<div class="control-group clear">
#Html.LabelFor(m => m.Email)
#Html.TextBoxFor(m => m.Email, new { type = "email", #class = "forbid-lt-gt" })
<span class="hint raise">Will be user as Username.</span>
<div class="error">#Html.ValidationMessageFor(m => m.Email)</div>
</div>
<div class="control-group clear">
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
<span class="hint raise">Length between 6 and 10 characters</span>
<div class="error">#Html.ValidationMessageFor(m => m.Password)</div>
</div>
<div class="control-group clear">
#Html.LabelFor(m => m.ConfirmPassword)
#Html.PasswordFor(m => m.ConfirmPassword)
<div class="error">#Html.ValidationMessageFor(m => m.ConfirmPassword)</div>
</div>
<div class="control-group action">
<button class="btn primary" type="submit">
<span>Sign up</span>
</button>
</div>
<div class="clear"></div>
}
And the file formBlocker.js to prevent multiple button click
$(function() {
$('form').one('submit', function () {
$(this).find('button[type="submit"]').attr('disabled', 'disabled');
});
//Enable submit button if data has changed
$('form').live("input", function () {
$(this).find('button[type="submit"]').removeAttr('disabled');
});
});
Usually all is fine, but sometimes it doesn't work and after user clicks several times on button the form can be sent several times to server. Early we had issue that after a click on submit button in IE form was sent to server twice. Now we don't have this issue but it was't fixed.
live is dead. dead. It was deprecated in 2.7 and removed in 2.9. DEAD!
I would use this approach:
var serializedData;
$(function () {
$('form').submit(function () {
var tempSerializedData = $(this).serialize();
if (tempSerializedData != serializedData)
serializedData = tempSerializedData;
else
return false;
});
});
Try this Not sure but this is working for me
$('form').one('submit', function () {
$(this).find('button[type="submit"]').attr('disabled', 'disabled');
setTimeout(function () {
$(this).find('button[type="submit"]').attr('disabled', 'disabled');
}, 20);
});