Blazor InputSelect - Client displays different value to server if List changed - select

I have an issue with the Blazor InputSelect control displaying an incorrect value at the client if the list changes. I post this article partly as a question but also as a solution
The InputSelect resides in a Blazor Component and is configured to provide a changed event to the parent control since various calculations must be performed which eventually affect other display elements and controls. Therefore, a simple bind of the value doesn't work for me and I use the three-parameter binding model.
The InputSelect displays an initial list. It is bound to a class instance property which is set on first load - this correctly reflects to the displayed value in the browser.
A user can choose a smaller set of values for the list. Even if this shorter list contains the selected value at the client, after setting the new list at the server, the client now displays the fist (incorrect) item in the list and not the correct value at the server. The bound property at the server still shows the correct value if other server interaction occurs and the value is inspected.
Looking at browser values, I noted that none of the option values within the client select had a selected property set. After changing my code to enforce a selected property the rest of the code worked as expected.
I assume that the internal state of the InputSelect and the html select element at the browser are not in step if the selected option is not set. Does anyone else suffer this issue?
<InputSelect Value="#ApertureValue" ValueChanged="#((double value) => SelectChanged(value))" ValueExpression="#(() => ApertureValue)" class="form-control form-control-sm">
#foreach (Aperture i in Aperture.GetApertures(PreferredWorkingStopsInUse))
{
<option value=#i.ApertureValue>#i.ApertureValueDisplay</option>
}
</InputSelect>
<InputSelect Value="#ApertureValue" ValueChanged="#((double value) => SelectChanged(value))" ValueExpression="#(() => ApertureValue)" class="form-control form-control-sm">
#foreach (Aperture i in Aperture.GetApertures(PreferredWorkingStopsInUse))
{
if (i.ApertureValue == ApertureValue)
{
<option selected value=#i.ApertureValue>#i.ApertureValueDisplay</option>
}
else
{
<option value=#i.ApertureValue>#i.ApertureValueDisplay</option>
}
}
</InputSelect>

Related

Angular 2 - Dynamic Reactive form with Radio Inputs build with FormBuilder, FormGroup, FormArray

Case:
I have an array of answers which I want to show in the view as radio inputs. When one of the answers is already answered it must be [checked] and if it's [checked] a textarea shows, so far so good.
Next I want to check another radio input and I want the current selected to be deselected and its textarea hidden, then the new selected radio input should be [checked] and it's textarea should show.
I use the FormBuilder and FormArray and have following issues.
I can't use index without intrapolation, I see many examples where the index is used without.
If I select another radio input, first my data disappears and it's not checked and on the second click it get's checked but now both are checked.
- I don't have access to the checked event, I can show it in the view with {{tempVar.checked}} as you can see above, if I use a template variable #tempVar, but I don't have access to it in the textarea below *ngIf="tempVar.checked". If I do use it in the ngIf I get the following error
Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.
Questions:
Is this the right approach?
An example of a Reactive Dynamic form with FormBuilder and FormArray with Radio inputs
Here is my code
https://gist.github.com/webwizart/121c85a0f316f47977cc0c99455af7bf
I would think using the tags should be reserved for unique identifiers? I wouldn't be surprised if dom renderer will update all elements with the same id.
Not sure if this will help, but you could use an answer view model instead (containing the same data) but that also has a 'checked' property
This way you can be sure that it will behave as you would expect.
e.g.: (in your component.ts)
let answers = this.question.Question.PossibleAnswers
.map(a =>
{ return Object.assign({}, a, { checked: false });
}
);
then in html you use: 'answer.checked' instead of 'radio.checked'
ps: also you could use ng-container instead of span, so you don't have an extra DOM imprint in your html

Build and interact with checkbox in Scala and Play Framework

I am new to Scala and the Play Framework. My goal is to display a checkbox in a view with values from a model. I would also like to grab those checkbox values from the view, process in a controller (make sure at least one value is selected), and add to a record in a model.
I have my controller built which displays the view and passes the checkbox values:
public Result addProfile() {
List<Service> services = Service.find.all();
return ok(profile.render(form(ProfileRegister.class), services));
}
I have my view built:
#(profileForm: Form[Application.ProfileRegister], servicesList: java.util.List[Service])
#main(null) {
#for(service <- servicesList) {
<input type='checkbox' name='servicesThis' value=#service>#service <br>
}
}
However, when the view displays, it looks like this:
I would like to have a checkbox appear -- it just displays text with no box to check. I wanted to also show the value of each record, such as the name property/field.
I would appreciate any help on this.
Thanks!
Try to put the value between double or single quotes, i.e. value="#service"
I got it to work with this:
#for(service <- servicesList) {
<label><input type="checkbox" name="services" value=#service.name><span>#service.name</span></label>
}
What is the best way to grab those checked values (multiple values) in a controller? And how to display if that record is opened for editing?
I appreciate the help.

Fetching visible text from a dropdown in protractor

I am trying to fetch visible text from a dropdown which does not have a selected option.
For dropdown which has selected option, i am using below code to fetch value from dropdown.
DenominationDropdown = element(by.css('[id*="MainContent_uxDenomination"] select'));
expect(DenominationDropdown.element(by.css('[selected="selected"]')).getText()).toBe('All Denominations');
In my second dropdown, there is selected value is not getting populated. I want to fetch current visible value (default value) which in my case is "All Dates" but below code is not working as there is no selected value.
DatesDropdown = element(by.css('[id*="MainContent_uxDates"] select'));
expect(DatesDropdown.element(by.css('[selected="selected"]')).getText().toBe('All Dates');;
Can someone please suggest a way in protractor to read current visible text or default value of dropdown?
HTML of dropdown:
<select name="ctl00$ctl00$ctl00$ctl00$body$body$MainContent$MainContent$uxDates" id="ctl00_ctl00_ctl00_ctl00_body_body_MainContent_MainContent_uxDates" class="ClassName">
<option value="%">All Dates</option>
<option value="Option1">Option1</option>
<option value="Option2">Option2</option>
.......
</select>
If it doesn't actually have the attribute selected=selected in the HTML, there should be another way. I tried this in my app on a dropdown and it worked fine:
var el = element(by.model('myDropdown')).$('option:checked');
expect(el.getText()).toEqual('test');
Note the above was for a dropdown, I originally thought it would be option:selected but that threw an invalid locator error. I have done this for radios in the past too:
var el = $('input[type=radio]:checked');
And, in case you werent aware, the $ is syntax equivalent to element(by.css())
getText() should return you the visible text only, by definition, which means that, if you call it on your select element, you should get the currently "selected" option:
expect(DatesDropdown.getText()).toEqual('All Dates');
In the case that doesn´t work with $.('option:checked'). you can try with add to end element(by.css('option:checked'));
var el = element(by.model('myDropdown')).element(by.css('option:checked'));
expect(el.getText()).toEqual('test');

jQuery: Select all 'select' elements with certain val()

Does anyone know of an easy way, using jQuery, to select all <select> elements whose val() attribute yields a certain value?
I'm trying to do some validation logic and would like to just select all those elements with a single selector, then apply a warning class to each of their parents. This I know how to do once I select all the elements, but I didn't see a selector that handles this case.
Am I going to have to select all of the <select> elements into a selector, then iterate through them and check each of their values? I was hoping there would be a simpler way.
Thanks.
Why doesn't select[value=x] work? Well firstly because <select> doesn't actually have a value attribute. There is not a single value of a select box: there may be no selected options (there shouldn't normally be, but there can be in at least IE), and, in a <select multiple>, there can be any number of selected options.
Even input[value=x] doesn't work, even though <input> does have a value attribute. Well, it does work, it just doesn't do what you think. It fetches the value of the value="..." attribute in the HTML, not the current value you have entered into the form. The value="..." attribute actually corresponds to the defaultValue property and not value.
Similarly, option[value=x][selected] doesn't work because it is checking the <option selected> attribute from the HTML source (selected attribute -> defaultSelected property) and not the current selectedness of the option (selected property not attribute) - which might have changed since the page was loaded.
Except in IE, which gets the value, selected etc form attributes wrong.
Except (again): Tesserex's example may seem to work, and the reason for that is that that it's using a non-standard jQuery-specific selector, :has. This causes the native querySelectorAll methods of modern browsers to fail, and consequently jQuery falls back to its own (native JavaScript, slow) selector engine instead. This selector engine has a bug where it confuses properties for attributes, allowing [value=x] to do what you expected, and not fail like it should! (Update: this is probably no longer the case in newer jQuery versions.)
Summary: form field state checking and selectors don't mix. Apart from these issues, you also have to worry about escaping issues - for example, what if the value you want to test against contains quotes or square brackets?
So instead, yes, you should check it manually. For example using a filter:
$('select').filter(function() {
return $(this).val()==='the target value';
}).parent().addClass('warning');
(There is a value property in HTML5 and supported by modern browsers, that when you read it gives you the value of the first selected <option>. jQuery's val() is safe to use here because it provides the same method of getting the first selected option even on browsers that don't support this.)
The existing answers don't work on select tags, but I found something that does. Ask for a select that has a selected option.
$("select:has(option[value=blah]:selected)")
You can use :
$("select[value=X]");
where X is the value against which you want to check the select's value.
Attribute selectors Is what you're looking for I believe.
Something like $+('element[attribute="value"]')
See also:
*= anywhere
^= starts with
$= ends with
~= contains word
etc.
You can create a change event that puts the value in a custom attribute on the select element whenever the value changes. You can then use a simple selector to find all of the select elements that have that value. For example:
$("select").on("change", function (e) {
var $select = $(e.currentTarget);
$select.attr("select-value", $select.val());
});
And then you can do this:
var $matches = $("select[select-value='" + searchVal + "']");
$matches will have all of your matching selects.
This is a lot easier than having to iterate through elements. Remember to set select-value to the initial value when rendering the page so you don't need to trigger a change event for each select so the select-value is set.

MVC Html.textbox/dropdown/whatever won't refresh on postback

OK, let's start with the Html.Textbox. It is supposed to contain text read from a file. The file read is based on what the user picks from a dropdown list.
The first time it is fine. The user picks a value from the dropdown list. The controller uses that value to read some text from a file, and returns that text to the view via the view model. Everything is fine.
THen the user picks another value from the dropdown list. The controller reads a new value from a file and returns it via the view model. Debugging to the LINE BEFORE THE HTML.TEXTBOX is set in the view shows that the model contains the correct value. However, the textbox itself still shows the PREVIOUS value when the page displays!
If I switch from Html.Textbox to a plain input, type="text" html control, everything works fine. That's not so hard, but the same thing happens with my dropdown list -- I can't set the selected value in code. It always reverts to whatever was chosen last. Rendering a "select" tag with a dynamically-generated option list is a pain. I would love to be able to use Html.Dropdown.
What am I missing here?? This is such a simple thing in webforms!
When you post a form, the values that are posted are put into ModelState. When the HtmlHelper renders an html iunput element, e.g. Html.TextBoxFor(x => x.FirstName), it'll search various locations to get the value for the textbox... ModelState is before ViewData.Model in the list of locations. So there for, the previously posted value will appear in your textbox.
To fix this you could clear the ModelState value or update the ModelState value. BUT I would kinda view that as a hacky way of getting around the problem.
The real issue has more to do with the flow of the posts and requests. I would personally look into that and maybe implement the PRG (Post Redirect Get) pattern.
HTHs,
Charles
Following on from what Charles/Charlino said:
Model binding updates the ModelState object, which contains validation and model binding errors that are collected during model binding.
Inside an action method, model binding has occurred already to update the model, and generated the ModelState object. If you now update the value on the model inside the action, you must also manually update the model state (since the helpers use it to generate their HTML). Below is an example:
model.CaptchaIsValid = CaptchaService.ValidateAndExpireCaptcha(model.CaptchaAttempt);
if (!model.CaptchaIsValid)
{
ModelState.AddModelError("CaptchaAttempt", "Incorrect - please try again");
}
// I'll clear the value on each attempt, to force them to re-enter a CAPTCHA.
model.CaptchaAttempt = string.Empty;
// Since I updated the model, I must create a new ValueProvider result...
ValueProviderResult clearedValue = new ValueProviderResult(
model.CaptchaAttempt,
model.CaptchaAttempt,
CultureInfo.CurrentCulture);
// ... and update the ModelState's value.
ModelState.SetModelValue("CaptchaAttempt", clearedValue);
The biggest issue I see here is that you are trying to do a postback within MVC. That model is really not supported, and is actually way more trouble than it is worth (as it seems you are finding out). I would recommend using Ajax to update the contents of the dropdown dynamically.