I'm new to ASP.NET MVC but I haven't been able to find an explanation for this.
My questions is regarding the difference in the value attribute in the generated HTML when I use #HtmlTextBox() vs. #HtmlTextBoxFor().
I can set the initial value for an <input> using #Html.TextBox() like this:
#Html.TextBox("Phone", "Initial Value", htmlAttributes: new { id = "txt_phone" })
The generated HTML is just what you'd expect:
<input id="txt_phone" name="Phone" type="text" value="Initial Value" />
Please notice the generated value attribute above.
Using #HtmlTextBoxFor() is a different. Please note that I have a very simple model in my view. It has a Phone property which is a String.
Here's an attempt at setting an initial value using #Html.TextBoxFor():
#Html.TextBoxFor(x => x.Phone, htmlAttributes: new { id = "txt_phone", value="Initial Value" })
The generated HTML, however, does not reflect the value attribute:
<input id="txt_phone" name="Phone" type="text" value="" />
My first question is, "why did the generated HTML not reflect the 'Initial Value' text in my value attribute?"
As many of you know, the "right way" to set the initial value with #HtmlTextBoxFor() is like this:
#Html.TextBoxFor(x => x.Phone, htmlAttributes: new { id = "txt_phone", Value = "Initial Value" })
But look at the generated HTML:
<input Value="Initial Value" id="txt_phone" name="Phone" type="text" value="" />
As you can see it generates a Value attribute (with a capital V) yet it still generates a value attribute with a lowercase v and an empty string!.
My second question then, is, why does #Html.TextBoxFor() require a captial V in Value yet still generate a lower-case v, value with an empty string?
Thanks
The answer to "why?" is because this is not the way you're supposed to pass a value. The HTML helpers use a bit of fairly complex logic to determine what the value of a field should be, and because it varies based on a number of different circumstances, your attempt at adding a manual value are largely ignored.
The first place Razor looks for a value is in ModelState, which is composed of the data from Request, ViewData and ViewBag. Then, it looks on the view's Model. Finally, it will fallback to the "default" value, which really only applies with the non-For helpers, where you can specify the value to default to. The reason you can't do the same with the For helpers is because they are bound to an actual property, and therefore, take that property's value, even if it's just the default of null or 0 or something.
Long and short, if you want to bind to a property and have it default to a specific value, then that value needs to be the default for the property. For example:
private string phone;
public string Phone
{
get { return phone ?? "Initial Value"; }
set { phone = value; }
}
Now, the property itself will always return "Initial Value" if it's previously unset, so your form field will as well.
Related
when i try to typetext as string on an input with type=number the browser display different value
var items = ["15300", "06500", "15400","24500","30580","77104","92730"];
const zipcode =items[Math.floor(Math.random()*items.length)];
console.log(zipcode);
return String(zipcode)
}
.typeText(AddressesLocators.txt.txtZipcode,await Utils.getRandomZipcode(),{ replace: Boolean })
This is because when setting the "type" attribute of an HTML input element to "number", the browser expects the entered value to be a valid number and therefore may attempt to convert the entered value to a number.
If you enter a string like "15300" in an input with type="number", the browser will try to convert the string to a number, in which case the resulting value will be 15300. However, if you enter a string like "06500 ", the browser will interpret the value as an octal number and then convert it to decimal, which will result in 3328 instead of 6500.
To avoid this behavior, you can use an input with type="text" instead of type="number" if you want the entered value to be treated as a string. Or, if you need to use type="number", make sure the value you enter is a valid number and does not start with a leading zero, such as "6500" instead of "06500".
I hope this helps.
I want to allow a user to provide a list of one-word attributes without parameter values. For example,
<container row crosscenter wrap spacearound ...>
which results in something like this in container.html
<div [ngClass]="{ 'flexDisplay': true, 'directionRow': isRow, 'directionCol': isCol, 'contentSpaceAround': isSpaceAround}" ...>
What I'm missing is how to set
#Input('row') isRow = false;
to true if 'row' was present in the container line.
Any ideas?
Thanks in advance.
Yogi
This can be handled in ngOnChanges. The value can be assigned either back to input property or to some object that will be passed to ngClass
ngOnChanges(changes: SimpleChanges) {
if ('foo' in changes) {
this.options.foo = true;
}
}
Since there's no way how inputs can become unassigned, there's no reason to provide bindings for them. #Attribute can be used instead:
constructor(#Attribute('foo') public foo: boolean|null) {
this.foo = (foo != null);
}
Using attributes for regular options isn't a good decision, design-wise. This prevents from setting them dynamically. Instead, it is always preferable to accept options input. If all options are supposed to be flags, it can be a string input that will be split and processed in ngOnChanges, like:
<container options="row crosscenter wrap spacearound">
or
<container [options]="'row crosscenter wrap spacearound'">
I think the answer to my question is to create directives for each of the "one-word" tags (attributes) I want to use.
:-)
I have created a form which allows the user to add additional text-inputs by clicking a button. The FormControls behind these inputs are stored in a FormArray inside of a FormGroup.
I want to provide a default value for these inputs, that is going to be submitted if they are pristine. If the user changes the value of the input, which changes it to dirty, I do not want the default value to be submitted or displayed.
I currently am displaying the inputs like this, as the placeholder attribute does exactly what I want, displaying the default name, only if the input has not been changed.
<div
formArrayName="names"
*ngFor="let server of names.controls; let i = index; trackBy:trackByFn">
<span>{{ i + 1 }}</span>
<input
type="text"
formControlName="{{i}}"
placeholder="{{defaultName}}">
</div>
To validate the names I have created the following validation function:
export function validateServerName(form: FormGroup): ValidationErrors | null {
const names: string[] = form.value[CREATE_FORM_KEY_NAMES];
for (const name of names) {
if (name.trim() === '') {
return {
invalidName: true
};
}
}
return null;
}
Here I am having trouble figuring out if the element is dirty or pristine, as form.value[key] only returns a string array, not an array of the FormControls.
I am looking for either an easier way to do what I am trying to achieve, or a way to validate the form properly.
you can check the control status using
if touched is true then its dirty
this.form.get('controlname').touched
and for pristine you can check like
this.form.get('controlname').pristine
UPDATE
for form array it will be something like
let val = this.user.get('<FormArray>') as FormArray;
console.log(val.at(index));
you can now use pristine and touched on this variable
I’m trying to pass a ViewData object of type double to an input field of type number with 1 decimal place. But the input field keeps empty. What am I doing wrong?
<p>
Debiet factor: <input name="FlowFact" type="number" value="#ViewData["FlowFact"]" step="0.1" autocomplete="off">
#String.Format("{0:N1} m³/h", #ViewData["FlowFact"]) <!--Result = 3,1 m³/h-->
</p>
The issue you're facing is what the ViewData["FlowFact"] is returning, which according to your #String.Format("{0:N1} m³/h", #ViewData["FlowFact"]) <!--Result = 3,1 m³/h--> it's 3,1.
That is not recognised as a number so it won't work. Either return a whole number or a decimal number. So instead of a 3,1, return a 3.1 or just a 3.
Otherwise change the input type to accept what you are passing.
I found the solution thanks to jamiedanq.
In my controller I was writing a double value to the #ViewData["FlowFact"] object. But in my view it was returning a value 3,0999 , which is not a correct value for the input type 'Number' because of the ",".
Instead of passing a double value to the object I've changed it to pass a string value and replace the "," with a ".":
Controller:
#ViewData["FlowFact"] = #String.Format("{0:N1}", MyDoubleValue).Replace(",",".");
View:
<p>
Debiet factor: <input name="FlowFact" type="number" value="#ViewData["FlowFact"]" step="0.1" autocomplete="off">
</p>
I have a widget with validation params such as "min" and "max". I want "min" to be set dynamically, because it depends on value contained in another widget.
<input id="test" type="text"
data-dojo-type="dijit/form/NumberTextBox"
name= "elevation"
required="true"
value="3000"
data-dojo-props="constraints:{min:-20000,max:20000,places:0},
invalidMessage:'Invalid elevation.'" />
How can I do something like min: testWidget.getValue()
Thanks.
All you need to do is use the _WidgetBase#set method. Here is the description from Dojo's API documentation:
Set a property on a widget
Sets named properties on a widget which may potentially be handled by a setter in the widget.
For example, if the widget has properties "foo" and "bar" and a method named _setFooAttr(), calling myWidget.set("foo", "Howdy!") would be equivalent to calling widget._setFooAttr("Howdy!") and myWidget.set("bar", 3) would be equivalent to the statement widget.bar = 3;
set() may also be called with a hash of name/value pairs, ex:
So with your widget reference you can simply do:
var elevationInput = dijit.byId("test");
var constraints = {
min: testWidget.getValue(); // or testWidget.get("value")
max: elevationInput.constraints.max
};
elevationInput.set("constraints", constraints);