<div class="editor-label" style="position:static">
<%: Html.LabelFor(Model => Model.Date, "Date")%>
<span style="padding-left:52px">
<%: Html.TextBoxFor(Model => Model.Date)%>
Here i want to set the readonly property to the textbox on a button click/Action Click. how do i do it.
At the initial page the data is been displayed as readonly and on the edit button click. This should be changed to editable textbox.I have almost seven textboxes i need to do the same for all.
If I understand your question correctly, this can be accomplished with a little javascript. Here's a simple example.
Render each textbox as readonly on page load:
<%: Html.TextBoxFor(model => model.Date, new { #readonly = "readonly" }) %>
Add a click handler for your edit button that will remove the readonly attribute from each textbox:
$("#editButton").click(function() {
$("#Date").removeAttr("readonly");
});
Use the following:
Html.TextBoxFor(m => m.Whatever, new {id = "", #class="",
placeholder="" #readonly="readonly"})
Hope this helps :)
I think you should put
#readonly = true
or
#readonly = *your-expression-here*
Related
I want to know if there is a better way to accomplish what I am doing or if my current approach is ok. My current approach is giving me a little trouble so I need to see what I can do about it all.
In my MVC web application, I have dropdown lists which are searchable (handled by KendoUI Widgets) and I allow the user to add missing data to the database table which serves those dropdown lists.
Example of Widget
#(Html.Kendo().DropDownList()
.Name("Manufacturer")
.Filter("contains")
.OptionLabel("-- Select --")
.DataTextField("ManufacturerName")
.DataValueField("ManufacturerName")
.NoDataTemplate("No Data Add Manufacturer")
.DataSource(source => {
source.Read(read => {
read.Action("GetManufacturers", "Cars");
}).ServerFiltering(false);
}))
The data is added via an ajax form in a partial view which is displayed using a bootstrap 4.0 modal trigger by a button in the no data template (see above example).
These dropdown lists appear in both Create and Edit views, in the Create view they work fine and as expected but within the Edit views, they have dictionary errors.
Create View
#model MyProject.Models.Cars
#using (Ajax.BeginForm("Create", "Cars", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "NotifySuccess",
OnFailure = "NotifyFailure"
},
new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
...Form goes here with widgets etc
}
#Html.Partial("_Manufacturer")
Popup form partial view
#model MyProject.Models.Manufacturer
<div class="modal fade" id="modal_addManufacturer">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
#using (Ajax.BeginForm("AddManufacturer", "Cars", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "Success",
OnFailure = "Fail"
}, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="form-group">
#Html.LabelFor(l => l.ManufacturerName, new { #Class = "form-label" })
#Html.TextBoxFor(i => i.ManufacturerName, new { #Class = "form-control" })
<input type="submit" value="Add" />
<input type="reset" value="Reset" />
</div>
}
</div>
</div>
</div>
</div>
These errors seem to stem from the fact that the Edit method in the controller passes an Id parameter. These leads me to the most obvious question, is this approach correct? Should I be using ajax forms in modals to create data on the fly like this especially when the models they use are causing problems when the Id parameter is used on views such as edit.
Can anyone offer some guidance on what I can do about this?
I have a kendo Grid for a class, and for that class I've built an editor template to produce a radio button for one of the fields.
This radio button doesn't reflect propertie's value and is always false, although I've checked the value, by printing it on the form, and I'm sure it's true. If I set a default value for that field, the radio button will reflect that value, regardless of the real value of the field.
I should note that I'm using a client template to display a text for that field, and it works fine.
This is the Grid:
#(Html.Kendo().Grid<Class>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(x => x.BActive).ClientTemplate("#= BActive ? 'Open':'Close' #");
/// removed for brevity
})
.Editable(editable => editable.Mode(GridEditMode.PopUp))
.DataSource(ds => ds.Ajax()
.Model(model => {
model.Id(x => x.SWhCode);
model.Field(x => x.BActive).DefaultValue(true);
})
)
)
And this is the lines that produce the radio button inside the editorTemplate:
<label>
#Html.RadioButtonFor(x => x.BActive, true, new { #class = "radio-inline" }) Open
</label>
<label>
#Html.RadioButtonFor(x => x.BActive, false, new { #class = "radio-inline" }) Close
</label>
bool type will be render in client like this
true => True
false => False
Have you try to inspect your element rendered in HTML? You'll see that the bool value transform into capitalize string. To overcome this you should change true and false in radio button with type string too.
Your view code should be like this
<label>
#Html.RadioButtonFor(x => x.BActive, "true", new { #class = "radio-inline" }) Open
</label>
<label>
#Html.RadioButtonFor(x => x.BActive, "false", new { #class = "radio-inline" }) Close
</label>
While creating a custom plugin, that Ajaxifies any forms that are not already Ajaxified by unobtrusive Ajax, I noticed that my partial/layout code failed to display on post-back with a normal Unobtrusive Ajax form:
For my other partial-update plugins, I conditionally render pages as partial (for ajax requests) or full with layout (for normal requests) like this:
public ActionResult AjaxForm()
{
if (!Request.IsAjaxRequest())
{
ViewBag.Layout = "_Layout.cshtml";
}
return PartialView();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AjaxForm(AjaxFormModel model)
{
if (!Request.IsAjaxRequest())
{
ViewBag.Layout = "_Layout.cshtml";
}
if (ModelState.IsValid)
{
return PartialView("Success", model);
}
return PartialView(model);
}
When it came to testing a normal unobtrusive Ajax form, I used this test view, which updates just its own element UpdateTargetId="FormPanel":
#using (Ajax.BeginForm("AjaxForm", null, new AjaxOptions() { UpdateTargetId = "FormPanel" }, new { id = "FormPanel" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.AddressLine, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.AddressLine, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<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>
}
If I remove the test if (!Request.IsAjaxRequest()), and return the full page with master page/layout, it renders the result just fine where the form was.
Fiddler shows the "success" view is returned in either case, but it does not do anything without the layout present.
Q. What is it in a masterpage/layout that unobtrusive Ajax requires in order to extract content and replace the specified element
Update:
To make things worse it actually works correctly the first time, but not if I ajax load the same form again.
A: Forms must have unique IDs!
There are loads of issues about unique IDs on SO, which browsers generally cope with, but the one you cannot ever break is having two forms loaded with the same id. Only one is visible to JavaScript/jQuery!
My problem was caused by a duplicate form ID. You should not insert the result page back in to the form itself (leaving the form element intact).
When I reloaded the original form, dynamically in a slideshow-style control, I wound up with duplicate form ID's.
This meant Unobtrusive Ajax could only see the first form in the DOM!
Solution (do not set Ajax forms to update themselves):
Set UpdateTargetId to an element above the form, never the form itself if you load panels dynamically.
Fix to my example view (surround form with a target panel):
<div id="FormPanel">
#using (Ajax.BeginForm("AjaxForm", new AjaxOptions() { UpdateTargetId = "FormPanel" }))
I must be missing something, silly, but here is the problem.
I have a Create action on the Transactions controller. The Create.cshtml uses jQuery to post the form to the server using a call to $.ajax. Debugging shows that everything arrives on the server as expected. I use the form data to update a record: this works fine too. I then return a partial view, passing a model to the view with default data. I can debug and verify that the model is passing nulls and 0s, ie, the default data for my model.
Problem is, what gets sent back to the browser in the response is the old data...!
I can see no reason why. Hopefully, you can...
Note: I am not using any form of output cache.
EDIT 1:
The caching is not happening in the browser. The reason I say that is that I can see in Firebug the response of the call to the AjaxCreate Action. I can also see this in Fiddler.
EDIT 2:
If you look at the code for the Partial View, you will see that each dropdownlist or textbox has the value of #Model.Transaction.[Property] printed out beside it. This, bizarrely, shows the correct value, ie, the defaults for my Transaction object, but the dropdownlists and text boxes stick with the values that were posted to the server rather than the default values for the property each one is supposed to render.
EDIT 3:
I have included the following image, so you can see the values printed to the right of each control that are being passed in. And yet the controls reflect the old data posted to the server in the previous $.ajax call. (The comment shows a date time at the moment of creating the view model, that way I could see things updating).
EDIT 4:
I have found that replacing #Html.EditorFor(...) (see view code below) with #Html.TextBox helpers removes the problem. So, what seems to be happening is that the EditorFor helpers are causing the problem. Why? I have no idea, but will post another, more specific question.
Code and markup as follows:
jQuery:
$(document).ready(function () {
$('input[name="nextRecord"]').live('click', function () {
var theForm = $(this).closest('form');
if ((theForm).valid()) {
var buttonText = $(this).val();
var action = "/input/Transactions/AjaxCreate/";
if (buttonText === "Reset") {
clearForm(theForm);
}
else {
var targetElement = $('#CreateDiv');
var _data = theForm.serialize() + '&nextRecord=' + $(this).val();
$.ajax({
url: action,
data: _data,
cache: 'false',
type: 'POST',
dataType: 'html',
success: function (html) {
$(targetElement).html(html);
createDatePickers(targetElement);
jQuery.validator.unobtrusive.parse(targetElement);
}
});
}
}
return false;
});
});
Partial View:
#model FlatAdmin.Domain.ViewModels.TransactionViewModel
#* This partial view defines form fields that will appear when creating and editing entities *#
<div class="editor-label">
Fecha
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Transaction.TransactionDate, new { #class = "date-picker" })
#Html.ValidationMessageFor(model => model.Transaction.TransactionDate) #Model.Transaction.TransactionDate.ToString()
</div>
<div class="editor-label">
Origen:
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Transaction.IdFrom, ((IEnumerable<FlatAdmin.Domain.Entities.Account>)Model.FromAccounts).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.AccountName),
Value = option.AccountId.ToString(),
Selected = (Model != null) && (option.AccountId == Model.Transaction.IdFrom)
}), "Choose...")
#Html.ValidationMessageFor(model => model.Transaction.IdFrom)#Model.Transaction.IdFrom
</div>
<div class="editor-label">
Destino:
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Transaction.IdTo, ((IEnumerable<FlatAdmin.Domain.Entities.Account>)Model.ToAccounts).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.AccountName),
Value = option.AccountId.ToString(),
Selected = (Model != null) && (option.AccountId == Model.Transaction.IdTo)
}), "Choose...")
#Html.ValidationMessageFor(model => model.Transaction.IdTo)#Model.Transaction.IdTo
</div>
<div class="editor-label">
Monto
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Transaction.IdCurrency, ((IEnumerable<FlatAdmin.Domain.Entities.Currency>)Model.AllCurrencies).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.CurrencyName),
Value = option.CurrencyId.ToString(),
Selected = (Model != null) && (option.CurrencyId == Model.Transaction.IdCurrency)
}))
#Html.EditorFor(model => model.Transaction.Amount)
#Html.ValidationMessageFor(model => model.Transaction.Amount) #Model.Transaction.Amount
</div>
<div class="editor-label">
Comentario
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Transaction.Comment)
#Html.ValidationMessageFor(model => model.Transaction.Comment)#Model.Transaction.Comment
</div>
View:
#model FlatAdmin.Domain.ViewModels.TransactionViewModel
#using FlatAdmin.Domain.Entities
#{
ViewBag.Title = "Nueva Transaccion";
}
<h2>#ViewBag.Title</h2>
<div>
#Html.ActionLink("<< Lista de Transacciones", "Index")
</div>
<br />
<div id="InputPanel">
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Elegir Actividad</legend>
<div class="editor-field">
#Html.DropDownListFor(model => model.Transaction.IdCostCentre, ((IEnumerable<FlatAdmin.Domain.Entities.CostCentre>)Model.AllCostCentres).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Name),
Value = option.CostCentreId.ToString(),
Selected = (Model != null) && (option.CostCentreId == Model.Transaction.IdFrom)
}), "Actividades...")
</div>
</fieldset>
<fieldset>
<legend>Transaccion</legend>
<div id="CreateDiv">
#Html.Partial("_Create", Model)
</div>
<p>
<input type="submit" name="nextRecord" value="Proxima Transaccion >>" />
</p>
<p>
...o sino, para guardar y volver a la lista de transacciones:<br /><input type="submit" value="Guardar" />
</p>
</fieldset>
}
</div>
Controller Action:
[HttpPost]
public virtual ActionResult AjaxCreate(Transaction transaction)
{
if (ModelState.IsValid)
{
service.InsertOrUpdate(transaction);
service.Save();
}
service.ChosenCostCentreId = transaction.IdCostCentre;
TransactionViewModel viewModel = new TransactionViewModel();
viewModel.Transaction = new Transaction();
viewModel.CostCentre = service.ChosenCostCentre;
viewModel.AllCostCentres = service.AllCostCentres;
viewModel.AllCurrencies = service.AllCurrencies;
viewModel.FromAccounts = service.FromAccounts;
viewModel.ToAccounts = service.ToAccounts;
return PartialView("_Create", viewModel);
}
#Darin Dimitrov came up with the answer in a related thread.
Essentially, the HtmlHelpers such as Html.EditorFor, Html.TextBoxFor, etc, check first in the ModelState for existing values, and ONLY then in the Model.
As a result, I needed a call to:
ModelState.Clear();
Ignorance is so painful.
Try explicitly setting the outputcache duration to 0 on your controller action.
I think the browser isn't supposed to cache POSTs but it seems to still do that sometimes.
I am creating a JQuery dialog where I have use data from a Model I want to validate, but the box is just closed, if I then click to open the dialog again I can see the red text indication errors, but it just closed.
function createEditorDialog() {
$('#floatsam_editor').dialog({ bgiframe: true, autoOpen: false, modal: true, width: 512,
buttons: {
'Close': function () { $('#floatsam_editor').dialog('close'); },
'Create': function () {
$('#flotsam_form').submit();
$('#floatsam_editor').dialog('close');
}
}
});
};
So the red text comes at the submit, but is closed right after, even though the validation failed.
Here is part of the ajax beginform that is shown
<div id="floatsam_editor">
#using (Ajax.BeginForm("CreateFlotsam" , "Flotsam", new { }, new AjaxOptions { HttpMethod = "Post", OnSuccess = "systematic_flotsam.successRequest" }, new { Id = "flotsam_form" }))
{
<div>
<fieldset>
<legend>Create Log Entries</legend>
<div >
<span class="editor-label">
#Html.LabelFor(m => m.Received.Date)
</span>
<span class="editor-field">
#Html.TextBoxFor(m => m.Received.Date, new { id = "flotsam_date", #class="datepicker", maxlength="10"})
</span>
<span class="editor-field">
#Html.TextBoxFor(m => m.Received.Hour, new { id = "flotsam_hours", maxlength="2" })
</span>:<span class="editor-field">
#Html.TextBoxFor(m => m.Received.Minute, new { id = "flotsam_minutes", maxlength="2"})
</span>
<span>
#Html.ValidationMessageFor(m => m.Received.Date)
#Html.ValidationMessageFor(m => m.Received.Hour)
#Html.ValidationMessageFor(m => m.Received.Minute)
</span>
</div>
<div>
<div class="editor-label">
#Html.LabelFor(m =>m.Flotsam.Informant)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Flotsam.Informant, new { #class = "flotsam_dialog_editor_field" })
#Html.ValidationMessageFor(m =>m.Flotsam.Informant)
</div>
</div>
Part of my model is here
[DisplayName("Informant:")]
[Required]
public object Informant { get; set; }
[DisplayName("Flotsam Nature:")]
[Required]
public object FlotsamNature { get; set; }
[DisplayName("Position of Loss:")]
[Required]
public object Position { get; set; }
And as seen it has 3 propertys which are required, but again it still closes if I dont enter anything in my ajax form
So how do I make the dialog box not close when model validation fails?
A very important note is that all this is done on one site and on client side, I do not want to reload the page.
Only close the dialog if the form is valid.
if($("#flotsam_form").valid())
{
$('#flotsam_form').submit();
$('#floatsam_editor').dialog('close');
}
This way it dialog will stay open and validation errors will appear
Since this is dyamically HTML content, you'll need to register the HTML that you wanted validated. This blog post should help you out.