Change label text on Input Box value change - c#

I am using Blazor framework with ASP.NET Core 3.0.
I have a Input Box and I added a Label HTML next to it. When user enters, say 5, in the Input Box, the Label should show calculated value of 5/2. That is, value of Input Box divide by 2.
In the Blazor framework, I am not understanding how to add jQuery.
Code is something like this:
<div class="col-sm-4">
<div class="justify-content-center mb-2">
<input type="text" class="form-control form-control-sm border border-secondary" #bind="myModel.CarWeight[index]" />
</div>
</div>
#if (myModel.AppType == "LC" || myModel.AppType == "LN")
{
decimal calcRes = Convert.ToDecimal(myModel.CarWeight[index]) / 2;
<div class="col-sm-4">
<div class="justify-content-center mb-2">
<label class="col-form-label"><b>calcRes</b></label>
</div>
</div>
}
Please note this line: myModel.CarWeight[index]
When the page is loaded, it creates an entry Form of 5 rows and 2 columns. 5 input boxes. When user fills any of the input box, I want the corresponding label to show the calculation.

You can update bind value on specific event
#bind:event="oninput"
See https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-5.0
You get this very simple code
#page "/"
<input type="number" #bind="inputVal" #bind:event="oninput" />
<label>#(Convert.ToDouble(inputVal)/2)</label>
#code{
string inputVal = "0";
}

Maybe somebody will come up with better idea to achieve what you want, but currently you could try something like this with C# code (.NET 5.0.103):
#page "/SampleComponent"
<input type="number" #bind="Operations[0].Input" #oninput="#( (input) => Calculate(input, 0))"/>
<label>#Operations[0].Result</label>
<input type="number" #bind="Operations[1].Input" #oninput="#( (input) => Calculate(input, 1))"/>
<label>#Operations[1].Result</label>
#code {
public List<Operation> Operations = new List<Operation>();
protected override void OnInitialized()
{
base.OnInitialized();
Operations.Add(new Operation{Input = 0, Result = 0});
Operations.Add(new Operation{Input = 0, Result = 0});
}
public void Calculate(ChangeEventArgs input, int id)
{
float result;
if(float.TryParse((string)input.Value, out result))
{
Operations[id].Result = result/2;
}
else
{
Operations[id].Result = 0;
}
}
public class Operation
{
public float Input { get; set; }
public float Result { get; set; }
}
}

Related

Filling input boxes in Bunit blazor Unit test

I have a blazor page with some input boxes and a button to submit the data. There is then code to validate and upload the data to a database after passing validation.
#page "/register"
<h2>
Create account
</h2>
<EditForm Model="_model" OnSubmit="#Submit">
<div>
<div class="form-group">
<label>Display name</label>
<InputText #bind-Value="_handle" class="form-control" />
</div>
<div class="form-group">
<label>Email</label>
<InputText #bind-Value="_email" type="email" class="form-control" />
</div>
<div class="form-group">
<label>Password</label>
<InputText #bind-Value="_password" type="password" class="form-control" />
</div>
<div class="form-group">
<label>Re-enter password</label>
<InputText #bind-Value="_repeatPassword" type="password" class="form-control" />
</div>
<div class="d-grid">
<button type="button" class="btn btn-primary" #onclick="Submit">Create your account</button>
</div>
</div>
</EditForm>
<div>
Sign in
</div>
#code {
private object _model = new object();
private string _firstname;
private string _lastname;
private string _handle;
private string _email;
private string _password;
private string _repeatPassword;
// -- validate inputs -- //
// -- Add to Database -- //
var user = new User
{
Id = Guid.NewGuid(),
Username = _email.ToLowerInvariant(),
Handle = _handle,
Password = password,
PasswordSalt = passwordSalt,
Firstname = _firstname,
Lastname = _lastname,
CreatedOn = DateTime.UtcNow,
};
context.Users.Add(user);
await context.SaveChangesAsync(default);
}
Recently I decided to set up unit testing for my razor pages and I am currently stuck on how to verify that a user is actually being created with the given data. I will say I know that my code is working because I can see the correct data being added to the database but I don't want to test potential changes in the future by looking at the database. I would like to be able to test it by the unit test. Here is what I have so far, I think I am close but not quite sure how to fill the input boxes and then hit submit to see the user is created. Is this possible? My unit test code is below.
namespace ZachUnitTests.ZachUnitTests.Pages;
public class RegisterTests
{
[Test]
public void VerifyUserData()
{
// Arrange
using var ctx = new Bunit.TestContext();
// Act
var cut = ctx.RenderComponent<Register>();
var inputs = cut.FindAll(".form-group");
var input1 = inputs.Where(x => x.ParentElement.TextContent.Contains("Display name")).FirstOrDefault();
input1.Input("Zachrules123"); //doesn't work because there is no #oninput .. How do I fill this box?
var input2 = inputs.Where(x => x.ParentElement.TextContent.Contains("Email")).FirstOrDefault();
input2.Input("Zachrules123#gmail.com"); //doesn't work because there is no #oninput .. How do I fill this box?
var input3 = inputs.Where(x => x.ParentElement.TextContent.Contains("Password")).FirstOrDefault();
input3.Input("password"); //doesn't work because there is no #oninput .. How do I fill this box?
var input4 = inputs.Where(x => x.ParentElement.TextContent.Contains("Re-enter password")).FirstOrDefault();
input4.Input("password"); //doesn't work because there is no #oninput .. How do I fill this box?
cut.Find("button").Click();
//Assert
//User is created
}
}
The error message from bUnit tells you what other event handler are actually bound to the object. You can also check cut.Markup and see what event handler are bound. But it is likely onchange, so use the Change() method instead of Input().

Find the selected radio input label from an unsorted-list of list-items Selenium C# Xpath

A screenshot of that part of the page:
The HTML:
<ul id="c2231_Fields_147_Value" name="Fields_147_Value" cvlid="Cushion">
<li>
<input type="radio" name="Fields_147_Value" value="" id="c2231_Fields_147_Value-0">
<label for="c2231_Fields_147_Value-0">(not set)</label>
</li>
<li>
<input type="radio" name="Fields_147_Value" value="Low" id="c2231_Fields_147_Value-1">
<label for="c2231_Fields_147_Value-1">Low</label>
</li>
<li>
<input type="radio" name="Fields_147_Value" value="Max" id="c2231_Fields_147_Value-2">
<label for="c2231_Fields_147_Value-2">Max</label>
</li>
<li>
<input type="radio" name="Fields_147_Value" value="Moderate" id="c2231_Fields_147_Value-3">
<label for="c2231_Fields_147_Value-3">Moderate</label>
</li>
</ul>
in the above elements, one radio is selected,
And I want the label text corresponding to the selected radio input.
For example, if the radio of 'Max' , is selected , then I want to read the value 'Max'
There are 4 input radio and 4 corresponding labels under unsorted list.
Each list item is a set of one input of type radio and one label.
User can select only one input since it is radio type.
How to read the value of selected input using C# and xpath ?
I have written following code and xapths but only the 1st xpath returned values , and it does not support list of list of Iwebelement, I guess, therefor my logic of IsSelected is always coming as true.
But when i tried with xpath for collection of input and collection of label separately, both worked at inspection time,
but while running the code in visual studio ,both returned empty list.
============my code=========and xpaths=========
public IList<IWebElement> CushionItemsList { get { return driver.FindElements(By.XPath("//ul[#cvlid='Cushion']/li")); } }
public IList<IWebElement> CushionItemsListInputs { get { return driver.FindElements(By.XPath("//ul[#cvlid='Cushion']/li/input")); } }
public IList<IWebElement> CushionItemsListLabels { get { return driver.FindElements(By.XPath("//ul[#cvlid='Cushion']/li/label")); } }
public string GetSelectedCushionValue()
{
string cushionValue = string.Empty;
int x = CushionItemsListInputs.Count();
for (int i = 0; i < CushionItemsListInputs.Count(); i++)
{
bool selected = CushionItemsListInputs[i].Selected;
if (selected == true)
{
cushionValue = CushionItemsListLabels[i].Text;
}
}
return cushionValue;
}
===============================================

Insert a new section/component on drag and drop with Blazor

I am trying to make a new section/div/component to appear in the droparea upon the drop action.
For example, I make two blazor components <Calculator/> and <Counter /> which should be put in a dropzone's div depending on which one was dragged. So far I have two draggable elements:
#page "/"
<!-- draggable items-->
<ul>
<li draggable="true" #ondragstart="OnDragStart">drag Counter</li>
<li draggable="true" #ondragstart="OnDragStart">drag Calculator</li>
...
</ul>
Then I have multiple divs and among them dropzone divs. Depending in which zone I drop it, there the new component should be rendered:
<!-- drop zones-->
<div class="bg-primary">
<div class="row one">Test</div>
<div dropzone="move" class="row space"
#ondrop="OnDrop" ondragover="event.preventDefault();"></div>
<div class="row two"></div>
<div dropzone="move1" class="row space"
#ondrop="OnDrop" ondragover="event.preventDefault();"></div>
<div class="row three">Test</div>
</div>
My code is not doing much yet, only indicating what action is taking place:
<div>#DragStatus</div>
#code {
public string DragStatus = "test...";
public void OnDragStart()
{
DragStatus = "started";
}
public void OnDrop()
{
DragStatus = "dropped";
}
}
How would I indicate which of two elements was taken/dragged?
I have found a solution. It is more functional than professional. Just to give an idea.
On drag start event you can pass a variable of what is being dragged to a function:
<li draggable="true" #ondragstart='(() => OnDragStart("Counter"))'>drag Counter</li>
<li draggable="true" #ondragstart='(() => OnDragStart("Calculator"))'>drag Calculator</li>
Then we need to know where this item is being dropped:
<div dropzone="move1" class="row space"
#ondrop='(() => OnDrop("first"))' ondragover="event.preventDefault();">B</div>
<div class="row two"></div>
From above we get two values {first, calculator} so it can be stored into tuple:
public List<Tuple<string, string>> myitems { get; set; }
= new List<Tuple<string, string>>();
public string place { get; set; } = "";
public string DragStatus = "test...";
Two functions will save this data only when an item is both dragged and dropped:
public void OnDragStart(string taken_a)
{
DragStatus = taken_a; //what is being dragged
}
public void OnDrop(string place_a)
{
place = place_a;
var item = new Tuple<string, string>(place, DragStatus);
myitems.Add(item);
}
Finally we can loop through a list of tuples inside dropzone div:
<div dropzone="move1" class="row space"
#ondrop='(() => OnDrop("first"))' ondragover="event.preventDefault();">
#foreach (var item in myitems)
{
#if (item.Item1 == "first")
{
#if (item.Item2 == "Calculator")
{
<Calculator />
}
#if (item.Item2 == "Counter")
{
<Counter />
}
}
}
</div>
It may work for some small data sets, because you need to put such loops under each dropzone.
Otherwise, one of the professional methods seems to be render trees. A good resource on it:
https://chrissainty.com/building-components-via-rendertreebuilder/

Enable/disable button based on text input in Blazor Server Side

I have a simple Blazor Server app and would like to enable a button when there is text in an input, and disable the button if there is no text in the input. I have looked at and tried numerous examples, and have not come up with a working solution yet. This is for a page with a search button, which requires valid text before the search button becomes enabled.
So, when as a user enters a character in the text input, button is enable. If the user deletes all the text in the input, button is disabled.
Here is the simplified code:
#page "/InputExample"
<h3>Input Example</h3>
<input type="text" #onkeyup="#(e => EnableButton(e))" #bind="myInputText" />
#if (disableState == true)
{
<input type="button" value="I'm disabled" disabled="#buttonState">
}
else
{
<input type="button" value="I'm not disabled">
}
#code
{
private string buttonState = "disabled";
private string myInputText = "";
bool disableState = true;
public void EnableButton(EventArgs args)
{
if (myInputText.Length == 0)
{
disableState = true;
}
else
{
disableState = false;
}
}
}
I'm not very experienced with Blazor yet and I don't know if this will work, but I can't say this in a comment, so....
Use #bind:event="oninput" so that the event fires on change instead of on loss of focus.
Get rid of the event handler and use set in the bound property to set disabledState.
Also, you could use the code you have and just see if calling StateHasChanged() in the handler does the trick.
#page "/InputExample"
<h3>Input Example</h3>
<input type="text" #bind:event="oninput" #bind="myInputText" />
#if (disableState == true)
{
<input type="button" value="I'm disabled" disabled>
}
else
{
<input type="button" value="I'm not disabled">
}
#code
{
bool disableState = true;
private string _myInputText;
public string myInputText {
get{ return _myInputText;}
set{
_myInputText = value;
disableState = _myInputText?.Length < 1 ? true : false;
}
}
}
I'm also not very familiar with the Blazor, but if you want to achieve this by regular JavaScript in your Blazor app, you can add the function to .cshtml file (_Host.cshtml)
JS function:
function changeValue() {
var edValue = document.getElementById("myInputId");
var s = edValue.value;
if (s.length === 0) {
document.getElementById("myBtn").setAttribute("disabled", "true");
document.getElementById("myBtn").value = "I'm disabled";
} else {
document.getElementById("myBtn").removeAttribute("disabled");
document.getElementById("myBtn").value = "I'm not disabled";
}
}
And then can use it on .razor page e.g (Index.razor)
Index.razor
<input id="myInputId" type="text" onInput="changeValue()">
<input type="button" id="myBtn" value="I'm disabled" disabled="">

How to read the data in a razor variable , assigned by a checkbox from a controller

My View has a list of rows for Edit , and each row has multiple checkbox . So I want to index each checkbox value with its corresponding row index.
For this I have in view :
List<string> FilterIds =new List<string>();
.
.
.
<td width="200px">
<div class="form-group">
<div class=" text-left">Apply Filter(s)</div>
<div class="col-md-10">
#foreach (var item in ViewBag.Filters)
{
<input type="checkbox" value="#item.FilterId" name="#FilterIds"/>#item.FilterId
<text> </text>
//FilterId[i] = FilterIds;
}
And my controller looks like this :
public ActionResult Edit([Bind(Include = "Conf_ActionTypeCTAMeta_V1_Id,Conf_CTAId,Conf_Clicklistid,ApprovedBy,DateApproved,EditedBy,DateEdited,Conf_TrackingActionTypeUnique_Id,ConfMarketid,MarketFilterId")] Conf_ActionTypeCTAMeta_V1[] conf_ActionTypeCTAMeta_V1, List<string> FilterIds)
Any quick solutions , how I can read the checked value per row ?
You have to create a view method for control every value's checkbox and you have to use CheckboxFor for bind it with model i couldn't help correctly because i don't know well too but i had a problem like this i used many textbox with data
This is my question and answer worked at me it's can be helpful: How can i take many textboxes' value on Post in MVC
And if you want to examine my solution (Page2.cshtml): https://github.com/kadirkalkan/WorkCubeFormMvc
I got this done, using 2 checkboxes and sync. them with javascript.
<ul>
#foreach (var item in ViewBag.Filters)
{
<li>
<input type="checkbox" id="fltrids#(i+1)#(item.FilterId)" value="#item.FilterId" name="c" + #i onclick="synch(#(i+1)#(item.FilterId))" style="width:5%; height:5%; border:5px; outline:double" /><text> </text>#item.FilterId
<input type="checkbox" id="mtch#(i+1)#(item.FilterId)" value="#i" name="s" />
<text> </text><text> </text>
</li>
}
</ul>
and the javascript is a simple function ,
function synch(j) {
var a = "fltrids" + j;
var b = "mtch" + j;
//console.log("a-" + a + "---- b-" + b);
var x = document.getElementById(a).checked;
if (x == true) {
document.getElementById(b).checked = true;
}
else {
document.getElementById(b).checked = false;
}
}
In this code has little bit mistake.
when you post data view(html) page to server side that time map with action parameter and html input tag "name attribute". and the name is same then assign value into param.
replace #FilterIds to FilterIds because you define controller in "FilterIds" so.
<input type="checkbox" value="#item.FilterId" name="FilterIds"/>#item.FilterId
not need any extra variable to store selected value.
Using html input tag with razor syntax the razor syntax work for display purpose.
Update Action Method :
public ActionResult Edit([Bind(Include = "Conf_ActionTypeCTAMeta_V1_Id,Conf_CTAId,Conf_Clicklistid,ApprovedBy,DateApproved,EditedBy,DateEdited,Conf_TrackingActionTypeUnique_Id,ConfMarketid,MarketFilterId")] Conf_ActionTypeCTAMeta_V1[] conf_ActionTypeCTAMeta_V1, CheckBox checkBox)
Create DTO class like :-
public class CheckBox
{
public List<string> FilterIds1 {get;set;}
public List<string> FilterIds2 {get;set;}
public List<string> FilterIds3 {get;set;}
}
update name attribute
<input type="checkbox" value="#item.FilterId" name="checkBox.FilterIds1"/>#item.FilterId
<input type="checkbox" value="#item.FilterId" name="checkBox.FilterIds2"/>#item.FilterId
<input type="checkbox" value="#item.FilterId" name="checkBox.FilterIds3"/>#item.FilterId
if you row generate dynamic then you can use like this:
public ActionResult Edit([Bind(Include = "Conf_ActionTypeCTAMeta_V1_Id,Conf_CTAId,Conf_Clicklistid,ApprovedBy,DateApproved,EditedBy,DateEdited,Conf_TrackingActionTypeUnique_Id,ConfMarketid,MarketFilterId")] Conf_ActionTypeCTAMeta_V1[] conf_ActionTypeCTAMeta_V1, CheckBox[] checkBox)
DTO class is :
public class CheckBox
{
public int Id { set; get; }
public string Name { set; get; }
public int index { set; get; }
}
i is a index value
foreach (var item in ViewBag.Data)
{
<input type="checkbox" value="#item.Id" name="checkbox[#item.index].Id" id="checkbox[#item.index].Id"/>#item.Name <br />
<input type="hidden" value="#item.index" name="checkbox[#item.index].index"/>
}

Categories

Resources