ASP.Net MVC EditorTemplate wrong Id - c#

So I have a double field called Area. I print it this way:
<div>#Html.EditorFor(model => model.Area)</div>
My EditorTemplate for Double looks like this:
#{
var attributes = this.ViewData.ModelMetadata.ContainerType.GetProperty(this.ViewData.ModelMetadata.PropertyName).GetCustomAttributes(true);
var htmlAttributes = GAtec.AgroWeb.Basic.Ux.Web.Helpers.EditorTemplateHelper.GetAllAttributes(ViewData, attributes);
var decimalPlaces = htmlAttributes["data-format"].ToString().Split(',');
var value = decimalPlaces.Length > 1 ? Model.ToString("n" + decimalPlaces[1]) : Model.ToString();
#System.Web.Mvc.Html.InputExtensions.TextBox(this.Html, Html.NameFor(model => model).ToString(), value, htmlAttributes);
}
<script>
$(document).ready(function () {
$("##Html.IdFor(model => model)").restrictNumber();
});
</script>
Nice, but why the html element comes wrong as <input id="Area_Area" /> and the jQuery selector comes right as $("#Area") ?
Both NameFor and IdFor returns "Area" when I watch them on debbuging.
UPDATE:
My htmlAttributes(As #DarinDimitrov asked) returns this array:
["data-min": "0.0", "data-format": "0,2"]

What's the point of stuffing gazilions of inline scripts inside your view (one for each editor template), when you could simply append a class="number" to your input field and then externalize your javascript in a separate file (which is where javascript belongs) and simply use a class selector:
$(document).ready(function () {
$(".number").restrictNumber();
});

#System.Web.Mvc.Html.InputExtensions.TextBox(this.Html, "", value, htmlAttributes);
This resolved my problem. The point is, the MVC knows the model name so you don't have to say him what to print. If you do, it will concat with the model name. But why it does this, I really don't know.

Related

Place Javascript Variable within Razor Code

I have one JavaScript function which adds a row into the table with the selected value in a text box. But how will i place the selected value inside the razor code ?
var val = document.getElementById("tags").value;
var strHtml2 = '#Html.TextBoxFor(x => x.extraDoc.dr_name, new {Value="Place Val Here", #class = "input1", #readonly = true })';
No it is not possible, because .NET MVC is server side code and is evaluated before being sent to the client, and javascript is Client side code which runs only once it is ON the client.
Actually you can do one thing you can get the element by using Id.
#Html.TextBoxFor(x => x.extraDoc.dr_name, new {Value="Place Val Here", #class = "input1", #readonly = true })
Razor will generate id field for the TextBoxFor probably id will be something like this: extraDoc_dr_name (or) you can find it in browser developer tool.
then you can set it using javascript:
document.getElementById("extraDoc_dr_name").value = document.getElementById("tags").value;
Try this:
var val = document.getElementById("tags").value;
var strHtml2 = '#Model.extraDoc.dr_name' ;
Update:
Now i understand what you are trying to archive.
No, you cannot mix js variable inside razor code. You can assing a razor value to a js variable, but not a js variable to a razor variable(afaik)

MVC EditorFor Remove Indexed Name

I have model that is a list of another model such that ModelList : ModelSingle
In my razor view I am using
#model somenamespace.ModelList
#Html.EditorForModel()
This iterates though each ModelSingle and returns an EditorTemplate that is strongly typed to ModelSingle.
#model somenamespace.ModelSingle
#using(Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "formname" + Model.ID}))
{
#Html.AntiForgeryToken()
#Html.EditorFor(p => p.SomeField)
#Html.EditorFor(p => p.AnotherField)
}
Each of these templates contains a form that can be used to edit the single model. These are posted individually with my controllers method expecting
public ActionResult(ModelSingle model)
The problem I'm having is that the model is not binding correctly. With a Model as such
public class ModelSingle()
{
public string SomeField { get; set; }
public string AnotherField { get; set; }
}
the EditorTemplate is being told that it was part of a list so I get
<Form>
<input name="[0].SomeField"/>
<input name="[0].AnotherField"/>
<input type="submit" value="Update"/>
</Form>
I can't simply bind to the ModelList as it's not naming ModelList[0].SomeField and even if it was I don't think that would work for anything but the first item.
Is there anyway to make the EditorTemplate ignore the fact that it's model was part of a list or force a DropDownListFor, EditorFor etc.... to just use the field name without prepending the [i].
I know I can force a Name="SomeField" change but I'd rather have a solution that will reflect any changes made in the Model class itself.
EDIT - As Requested added a simplified example of the View and EditorTemplate being used.
The problem is related to a mismatch between the input names generated by your page model (which is a list), and the model expected by your action, which is a single item from your list.
When rendering a list, the default behavior is to render the indexed names like you've shown to us (the [#] notation). Since you want to be able to post any arbitrary item from the list, you won't know ahead of time what index is used. When the model binder looks at the request for your single object, it does not attempt to use the index notation.
I don't know what your requirements are from the user perspective - e.g. whether or not a page refresh is desired, but one way to accomplish this is to provide a jQuery post for the specific item being posted:
// pass jquery form object in
var postItem = function($form) {
var postBody = {
SomeField: $form.find('input selector') // get your input value for this form
AnotherField: '' // another input select for this item
}
$.ajax({
url:'<your action url>',
type: 'POST',
contentType:"application/json; charset=utf-8",
data: JSON.stringify(postBody),
dataType: 'json',
success: function(response) {
// do something with returned markup/data
}
});
}
You are manually serializing a single instance of your model with a json object and posting that. What you return from the action is up to you: new markup to refresh that specific item, json data for a simple status, etc.
Alternately, you can consider manually looping over the items in your collection, and using Html.RenderPartial/Html.Partial to render each item using your View template. This will short-circuit the name generation for each item, and will generate the names as if it's a single instance of ModelSingle.
Finally, a quick (but kind of ugly) fix would be to have your action method take a list of ModelSingle objects. I don't suggest this.
Edit: I missed some important aspects of posting json to an mvc action
Edit2: After your comment about hardcoded names, something like this could help:
var inputs = $form.find('all input selector');
var jsonString = '{';
$.each(inputs, function(index, element) {
var parsedName = element.attr('name').chopOffTrailingFieldName();
jsonString += parsedName + ":'" + element.val() + "',";
});
jsonString += '}';

How Can DeActivate Razor Html Encoding ?

In Razor view I have a Javascript function. This function take 2 URLS String in arguments and call AJAX to do operation.
When I generated Url string in Razor, Razor change the URLS. Like changed & to & and damage my query strings which used in my URL address. Also Html.Raw() has not work in this case.
What can I do ?
EXAMPLE:
In my Razor editor:
<a href="#" style="color:#0564c1;" onclick="PopUpStart('POST','','',200,100,'#(Html.Raw(address+"/index/?id="+baseObject.Id+"&"+"type="+dataTypeInt))','#Html.Raw(address + "/cancel/?id="+baseObject.Id+"&type="+dataTypeInt )','ReloadPage',true);return false;">
Edit
</a>
In result :
<a href="#" style="color:#0564c1;" onclick="PopUpStart('POST','','',200,100,'/PdfInstanceEdit/index/?id=1&type=270','/PdfInstanceEdit/cancel/?id=1`&`type=270','ReloadPage',true);return false;">
Edit
</a>
The URL address like :
address+"/index/?id="+baseObject.Id+"&"+"type="+dataTypeInt
Change to :
/PdfInstanceEdit/index/?id=1&type=270
In other world character & => &
Its usually a bad idea to try and combine server code and client strings inside the quotes of a property (ie onclick="something#(something())" )
Its better to just return the entire lot in a server side function
Here's how I would rework your code:
<a href="#" style="color:#0564c1;"
onclick="#Html.Raw(
String.Format(
"PopUpStart('POST','','',200,100,'{0}','{1}','ReloadPage',true);return false;"
, Url.Action("index",address,new{id = baseObject.Id, type = dataTypeInt})
, Url.Action("cancel",address,new{id = baseObject.Id, type = dataTypeInt})
)
)"/>
Edit
</a>
Also note the difference between #(Html.Raw()) and #Html.Raw() - you should use the latter!
As direct assignment of events such as onClick is frowned on these days, a better way to accomplish then may be through js:
Add a hidden field for Id and dataTypeInt to your page:
#Html.HiddenFor(model=> model.Id)
#Html.Hidden("dataTypeInt ", dataTypeInt)
Add an id to your anchor:
Edit
Then your script:
<script>
$(document).ready(function () {
readyLinks();
});
readyLinks = function(){
var id = $('#Id).val();
var dataType = $('#dataTypeInt').val();
var indexUrl = '/PdfInstanceEdit/index?id=' + id + '&type=' + dataType;
var cancelUrl = '/PdfInstanceEdit/cancel?id=' + id + '&type=' + dataType;
$('#editLink).on('click', function(){
PopUpStart('POST','','',200,100,indexUrl, cancelUrl,'ReloadPage',true);
return false;
});
};
</script>
You should use Html.Raw() as suggested in the comments, see the documentation.
As described in this thread, if you have a particular problem with the output encoded format, you could use the HttpUtility.HtmlDecode() function, see documentation.
#Html.Raw(HttpUtility.HtmlDecode(address+"/index/?id="+baseObject.Id+"&"+"type="+dataTypeInt))
But since this could be a solution I cannot address you problem precisely...
A friendly reminder: if you're trying to put a Javascript string inside an HTML attribute, the value must be encoded twice. It must first be Javascript-encoded, then that result must be HTML-encoded. You could inadvertently open an XSS hole in your site if you don't perform both encodings in the correct order.
Say you have a string s that you want to display to the client. You'd write your Razor markup as:
Click me
Note the explicit call to JavaScriptStringEncode. Then Razor's # syntax will auto-HtmlEncode this value before writing it to the response.

setting the value of textbox equal to address bar in MVC4?

How can I set the Textbox's value equal to address bar?
for example :
localhost:28362/?f=Ava
when we click on a button the value of textbox must set to : Ava
?
Try this, Add Query String Jquery Js(querystring-0.9.0-min.js) in solution
$("#ButtonId").click(function(){
$("#textBoxID").val($.QueryString("f");)
});
Here is Javascript function to get query string value:
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
Then you need to assign this value to a textbox. I would use jQuery:
$(function(){
$("#myTextBoxID").val(getParam("f"));
})
If you want a solution that uses MVC4 rather than JavaScript, define your controller method as:
public ActionResult Index(string f) {
return View(f);
}
In your view, you would then use one of:
#model string;
#Html.TextBoxFor(Model)
or
#model string
<input type='text' value='#Model' name='myValue' />
Obviously this is vastly oversimplified, but should give you a good starting point.

Pass hidden ID when textbox is changed

I have multiple textboxes, every textbox has a related hidden field, the hidden field's ID is a concatenation of a string with the model's ID (ex: "FormState25")
How can I pass the ID of a hidden field when a textbox being changed? I'm using the following code to detect textbox change:
$("#body-content-container").on('change', 'input[type="text"]', function () {
$("#FormState").val('dirty');
});
You can add custom attributes to the textbox tag itself that includes the Id of the hidden field, for example:
In View
#Html.TextBoxFor(model => model.Name, new { HiddenFieldId = "FormState" + Model.Id })
This way when a textbox get changed you can get the Id of the hidden field you already use to store whatever you want, and then modify the javascript to handle that hidden field's Id, like this:
Javascript
$("#body-content-container").on('change', 'input[type="text"]', function () {
var hiddenId = $(this).attr("HiddenFieldId");
$("#" + hiddenId).val('dirty');
});
The javascript will get the HiddenFieldId attribute of the corresponding hidden field from the textbox and change it's value. Try this and let me know..
You can use this to reference the element on which the anonymous function is defined, e.g.:
$("#body-content-container").on('change', 'input[type="text"]', function () {
$("#FormState" + this.attr('id')).val('dirty');
});
try this:
$("input[type=text]").click(function(){
var hiddenId = "FormState" + $(this).attr("Id");
var hiddenField = $("#" + hiddenId);
hiddenField.val("dirty");
});
EDIT:
if your hidden field rendered just after your inputbox then you can do the following :
$("input[type=text]").click(function(){
var hiddenField = $(this).next();
hiddenField.val("dirty");
});
hope this could help.
Here's another trick which I've used in the past. Enclose the two related input fields in a div (or other) element. Then use the fact that the text field and the hidden field are siblings to select the correct hidden field. Perhaps something like this (NOTE: I have not tested this example):
<div id="someId">
<input type="hidden" value="unchanged" />
<input type="text" value="some data" />
</div>
<script type="text/javascript">
var hiddenInput = $('#someId input:first')
var textInput = $('#someId input:last')
textInput.on('change', function() {
hiddenInput.val('modified');
});
</script>

Categories