I'm trying to achive a search functionality for Blazor-server where the idea is to use it anytime on the site by typing on a search box which causes the page to change the #Body for a component that shows the results of the search.
Currently I'm able to do the search well on the MainLayout but this is by having already a list there and the Body component either below or on top. What I need is to only show the List AFTER I input something on the search bar and to replace it with the Body.
Here is what works but whithout the issue I am having.
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" #oninput="(ChangeEventArgs e)=>SearchHandler(e)" />
<BrowseListShared #ref="BrowseListShared" />
#Body
code{
public string Searched { get; set; }
protected BrowseListShared BrowseListShared;
public void SearchHandler(ChangeEventArgs e)
{
Searched = e.Value.ToString();
BrowseListShared.UpdadeMe(Searched);
}
}
And this is my attempt at trying to make the replacement which gives me the error "Object reference not set to an instance of an object.", the Error shows when I type something in the search box.
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" #oninput="(ChangeEventArgs e)=>SearchHandler(e)" />
#if (setVisible){
<BrowseListShared #ref="BrowseListShared" />
}else{
#Body
}
code{
public string Searched { get; set; }
protected BrowseListShared BrowseListShared;
private bool setVisible=false;
public void SearchHandler(ChangeEventArgs e)
{
if (e != null && e.Value.ToString() != ""){
setVisible = true;
}else{
setVisible=false;
}
Searched = e.Value.ToString();
BrowseListShared.UpdadeMe(Searched);
}
}
Hope someone can give me some direction to deal with this, thank you.
Edit:
Adding if(BrowseLit != null) to avoid error does make it work with some issues.
1- the first character makes so it shows just the list without the search because on the first character the code doesnt have the reference yet for the BrowseListShared so it skips the BrowseListShared.UpdateMe for the first tipe.
2- On deleting the text in the box completely until its blank and typing again will cause this error 'Cannot access a disposed object.'
There shouldn't be an issue to add a small if-block, the following is a basic concept that works for me:
<button #onclick="#( () => test = !test )">test</button>
#if (!test)
{
#Body
}
else
{
<span>some other search content - use a component here
and pass the data as a parameter to it, and its OnParametersSetAsync
can fetch needed data: #test</span>
}
#code{
bool test { get; set; }
}
I would also suggest you try using parameters for the search details instead of a reference.
If you want to show a particular page with search results, you can consider navigating the user to that page (e.g., pass the search query as a route parameter to it) - then it will render only what you want in the #Body - which can range from nothing, to search results, to a lot of other things.
Related
I have a razor component with the following input. I currently use the "GetCourses" method to retrieve a list of courses, and everything works as expected upon button click. I would like to, however, be able to type in some string into the searchbox, and upon hitting the "enter" key, call the same "GetCourses" method. I have duplicated the "GetCourses" method and modified it to work with the #OnKeyDown event, but it does not work. In the debugger, the #OnKeyDown event is triggered with each key press, but it never binds a value to "this.inputValue." I want to capture all of the string characters in the searchbox, not one at a time, and why is it not binding?
<div>
<input type="text"
class="searchbox"
name="user"
placeholder="Search by course name or course ID"
#bind="#this.inputValue"
#onkeydown="#GetCoursesbyKey" />
</div>
<span>
<button class="searchbtn"
#onclick="#(T => GetCourses(inputValue))">
Search
</button>
</span>
#code {
public string inputValue { get; set; }
private async Task GetCoursesbyKey(KeyboardEventArgs? e)
{
var search = this.inputValue;
if (e.Code == "Enter" || e.Code == "NumpadEnter")
{
if (search != null)
{
//perform some logic
}
else
{
//perform some logic
}
//wait on some methods here
}
}
private async Task GetCourses(string search)
{
var search = this.inputValue;
if (search != null)
{
//perform some logic
}
else
{
//perform some logic
}
//wait on some methods here
}
}
Making this small change made the feature work perfectly. I do not have the technical analysis as to why, other than these functions accomplish what I was attempting to do.
<div>
<input type="text"
class="searchbox"
name="user"
placeholder="Search by course name or course ID"
#bind-value="#this.inputValue"
#bind-value:event="oninput"
#onkeydown="#GetCoursesbyKey" />
</div>
I'm creating a application using SyncFusion and Blazor. In this application I have a login page which looks like this:
Using this code:
<EditForm Model="#ModelValue">
<SfTextBox #ref="user" Placeholder="E-mail" Created="#onCreateUser" CssClass="custom-login" Type="InputType.Email" #bind-Value="#ModelValue.Email" required></SfTextBox>
<SfTextBox #ref="password" Placeholder="Password" Created="#onCreatePassword" CssClass="custom-login" Type="InputType.Password" #bind-Value="#ModelValue.Password" required minlength="7"></SfTextBox>
<SfCheckBox Label="Stay Signed In" #bind-Checked="rememberUser" CssClass="stay-signed-in-checkbox"></SfCheckBox>
<SfButton CssClass="forgot-password-button">Forgot Password?</SfButton>
<SfButton CssClass="login-button" OnClick="validateForm">LOGIN</SfButton>
</EditForm>
#code {
SfTextBox user;
SfTextBox password;
private bool rememberUser;
private User ModelValue = new User();
public void validateForm()
{
}
/*ICON*/
public void onCreateUser()
{
this.user.AddIcon("prepend", "oi oi-person");
}
public void onCreatePassword()
{
this.password.AddIcon("prepend", "oi oi-key");
}
}
In this form are html browser validation popups applied(automatically). These work kind of weird in my situation therefore i created a video illustration it properly:
https://drive.google.com/file/d/1PhETRPkgDag_DHWYlBFJL1qnodxDpaQ_/view?usp=sharing
As u can see the email field works fine, html form validation occurs every time when button is pressed. In the Password field this is not the case, theres required a minimum of 7 characters and when i press submit button with only 3 characters filled in im not getting any warnings.
Does someone know how to fix this?
If you want to use the html5 form validation, the minlengthattribute won't work. If you want to do that validation you should use pattern attribute and pass it like pattern=".{7,}". This is explained in this answer.
If you want to use the blazor validation (which is much better and recommended), you need to use data annotations in your User model.
For your particular case, you can use the MinLength attribute.
public class User
{
// other propeties
// Passing data annotations
[MinLength(7, ErrorMessage = "Password Min Length is 7")]
public string Password { get; set; }
}
And for the data annotations validation to work, don't forget that you need to have the DataAnnotationsValidator component inside the EditForm
<EditForm Model="#ModelValue">
<DataAnnotationsValidator />
#* rest of components *#
</EditForm>
I am trying to make my input text always be uppercase in a blazor input text field. I tried creating a custom InputText like the below but it doesn't update the binding (appears as uppercase but doesn't bind as such). What am I doing wrong here? Is there a better way?
#inherits InputText
<input #attributes="AdditionalAttributes"
class="#CssClass"
value="#CurrentValue"
#oninput="EventCallback.Factory.CreateBinder<string>(
this, __value => CurrentValueAsString = __value.ToUpper(), CurrentValueAsString.ToUpper())" />
Simplicity works for me.
<input type="text" oninput="this.value=this.value.toUpperCase()" #bind=CurrentValueAsString />
For simplicity and (in my opinion) UX reasons, let's assume that the user is allowed to type lowercase letters, but the application will ToUpper the input after they leave that field.
First, make a new component so we can reuse the logic. I called mine UppercaseTextInput.razor
<input value="#UserInput"
#onchange="async e => await OnChange(e)" />
#code {
[Parameter]
public string UserInput { get; set; }
[Parameter]
public EventCallback<string> UserInputChanged { get; set; }
private async Task OnChange(ChangeEventArgs e)
{
var upperCase = (e.Value as string).ToUpperInvariant();
await UserInputChanged.InvokeAsync(upperCase);
}
}
The private method OnChange gets called whenever the input loses focus. Change #onchange to #oninput to make this happen every keystroke.
Now you can use this component in another page or component. For example, in the index page:
#page "/"
<h1>Hello, world!</h1>
<UppercaseTextInput #bind-UserInput="UserInput" />
<p>You typed: #UserInput</p>
#code {
public string UserInput { get; set; } = "Initial";
}
In this example, I have "Initial" as the starting text, which will be printed inside the text box. As soon as you leave the element, the text inside will be transformed to be uppercase.
The benefit of using a component is that you can do a standard #bind- with your properties.
I was using an old reference to the input which was causing the error. There was a bug in the code though (if the input was null). The corrected version can be seen here:
#inherits InputText
<input #attributes="AdditionalAttributes"
class="#CssClass"
value="#CurrentValue"
#oninput="EventCallback.Factory.CreateBinder<string>(
this, __value => CurrentValueAsString = __value?.ToUpper(), CurrentValueAsString?.ToUpper())" />
The answer to this was easier than all the answers: it can be solved using CSS text-transform: uppercase;. This is all you needed and it doesn't take any processing power because it's included in the browser's engine.
I'm using MudBlazor.
I scratched my head for a while why the heck adding
Style="text-transform: uppercase;"
to <MudInput> is not working, even with !important attribute the default user agent style (text-transform: none;) was applied.
C# or JS seemed overkill for the task in my opinion.
What finally worked for me was adding
input {
text-transform: uppercase;
}
to the site's CSS sheet (index.css in my case).
This eventually overwritten the default user agent style.
Is it possible to two way bind or bind to an event in Blazor w/ non strings? I have done this with text without an issue but any other type of object is causing me issues.
For example, I have a method that executes when inputting text in a box which is based on the value inputted as well as several other inputs on the form.
<InputNumber step=".01" class="form-control form-control-xs" #bind-Value="#Salary" #bind-Value:event="onkeydown"/>
private decimal salary {get; set;}
public decimal Salary
{
get
{
return salary;
}
set
{
salary = value;
CalculationHere();
}
}
When I do this, I get the below error:
I have also tried passing it in as a parameter like so:
#oninput="#((ChangeEventArgs __e) => CalculationHere(Convert.ToDecimal(__e.Value)"
This also does not work as it causes an error when the textbox is empty and doesn't fire for all inputs (have tried on keydown as well). There are also a lot of parameters so if possible I'd like to avoid this.
I should also note that when I run this project, set a breakpoint in the method being called, and bind like the below, it DOES work. However, removing the breakpoint stops it from working. This has left me VERY confused.
<InputNumber step=".01" class="form-control form-control-xs" #bind-Value="#Salary" #oninput="(() => CalculationHere())"/>
Is there a best practice regarding this? I'm new to web development and Blazor itself is very new so I'm not sure what the best route to go here is... Any advice? Thanks!
When you tell Blazor that it should update the value of a variable via events such as onkeydown, it does not know what to do with the event args provided to it. To achieve a two-way binding in such a case, you need to do the binding manually.
Add an #oninput directive to your InputNumber Component with the value "#((e) => #employee.Salary = Convert.ToDecimal(e.Value))"
Your InputNumber Component should look like this:
<InputNumber step=".01" class="form-control form-control-xs" #bind-Value="#employee.Salary" #oninput="#((e) => #employee.Salary = Convert.ToDecimal(e.Value))" />
Now, whenever the input of your text box changes, the input event is triggered, and the ChangeEventArags is passed to you, you extract the value, convert it to decimal and assigned it to the #employee.Salary property.
This answer could be deduced from my first answer where I use
#oninput="#((e) => CalculationHere(e))"
to call the CalculationHere
Hope this helps...
The InputNumber component should be embedded in the EditForm Component whose Model attribute is set to your model employee
You should not add the #bind-Value:event="onkeydown". What for ? The default and the correct event for the binding is the onchange event and it deals appropriately with updating the Salary property.
Put this code in the Index page and run
<EditForm Model="#employee" OnValidSubmit="#HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText id="name" #bind-Value="#employee.Name" />
<!-- <InputNumber step=".01" class="form-control form-control-xs" #bind-Value="#employee.Salary" /> -->
<InputNumber step=".01" class="form-control form-control-xs" #bind-Value="#employee.Salary" #oninput="#((e) => CalculationHere(e))" />
<button type="submit">Submit</button>
</EditForm>
<p>Salary: #employee.Salary</p>
<p>After calculation: #calculation</p>
#code{
decimal calculation;
Employee employee = new Employee() { Name = "Davolio Nancy", Salary = 234 } ;
public class Employee
{
public string Name { get; set; }
private decimal salary { get; set; }
public decimal Salary
{
get
{
return salary;
}
set
{
salary = value;
//CalculationHere();
}
}
}
private void HandleValidSubmit()
{
}
void CalculationHere(ChangeEventArgs e)
{
calculation = Convert.ToDecimal(e.Value) * Convert.ToDecimal(1.2);
}
}
Well, the question is very simple.
I've got an webkit browser in an class file generated this way:
public static WebKit.WebKitBrowser mainBrowser = new WebKitBrowser();
Now I'm trying to login on an website automaticly. But the input fields aren't filled in.
I'm using this code to get to the point where the data needs to be filled in:
public void loginthen()
{
this.Controls.Add(globalVars.mainBrowser);
globalVars.mainBrowser.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(mainBrowser_DocumentCompleted);
globalVars.mainBrowser.Navigate("http://www.somesite.com/");
}
void mainBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var send = sender as WebKit.WebKitBrowser;
if (send.Url == e.Url)
{
MessageBox.Show("Inloggen");
globalVars.mainBrowser.Document.GetElementById("user").TextContent = "User Name";
}
}
The MessageBox is shown, and i get no error, but the input field isn't filled in.
The HTML of the input fields is this:
<input id="user" name="user" class="text" type="text" value="" onkeydown="if((e=window.event||event) && e.keyCode == 13 && $('#user').val() && $('#password').val()) $('#login_button').trigger('click');">
So my thought was... Am I using the TextContent wrong?
And can this (and triggering the button and so on) not be much easier be done with javascript?
So I googled and searched for it, but the only thing that I can find is how to call C# function from javascript or how to call an javascript function from C#. But I don't own these sites, so that won't work...
So what are your thoughts about it?
Instead of:
globalVars.mainBrowser.Document.GetElementById("user").TextContent = "User Name";
you should use:
globalVars.mainBrowser.Document.GetElementById("user").SetAttribute("value", "User Name");
You may use the TextContent property to set the content of a HTML tag such as <p />, <span /> or maybe <div />.
globalVars.mainBrowser.Document.GetElementById("myDiv").TextContent = "some div content";