Nothing happens when clicking search button on bootsrap and .net core - asp.net-core

I am trying to learn .net core and what I want to do is: I have a search bar and a GetDetail function in controller. I want to trigger that function when clicking search button according to text in form. But when I click button, nothing happens. I did not complete the trigger part but even if I simply redirect to another page with href, also nothing happens. Here is my search bar view code which taken from sbadmin2:
<div class="row justify-content-center">
<div class="col-6 p-3">
<div class="input-group">
<input type="text" class="form-control bg-light border-0 small" placeholder="Input" aria-label="Search" aria-describedby="basic-addon2" id="code">
<button class="btn btn-primary" type="button" action="/Books/GetDetail?">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</div>
and the function I want to trigger is a get request:
public IActionResult GetDetail(string codes)
{
var request = $"?codes={codes}";
var products = _httpTool.HttpGetAsync<List<Products>>($"{AppSettings.ApiUrl}/GetProducts{request}");
var productList = products.Result.ToList();
return Json(productList);
}
Why nothing is happening and how can I achieve this?
Thanks in advance!

try something like this:-
<form method="post" asp-action="GetDetail">
//clarify code
<input type="submit" value="Search" class="btn btn-outline-primary mt-1"/>
//clarify code
</form>
[HttpPost]
public IActionResult GetDetail(string codes)
{
var request = $"?codes={codes}";
var products = _httpTool.HttpGetAsync<List<Products>>($"{AppSettings.ApiUrl}/GetProducts{request}");
var productList = products.Result.ToList();
return Json(productList);
}
After clicking Searchyou see something will happen.

Related

How to delete from a database in Ajax?

I'm sure there are similar questions, but I searched both here and on Google and found no answer.
I have a list of products in the database. And I have a method that delete the current product by button. And it works great!
The problem starts when I try to make the button not POSTBACK
I know the problem is with the RETURN but if I do not write it, I have an error message because my method is - async Task
For what I need to change the method so that it works without changing the URL / postback?
index.cshtml-
<ul class="list-group list-group-lg list-group-flush list my--4">
#foreach (var prod in Model.ProductList)
{
<li class="list-group-item px-0">
<div class="row align-items-center">
<div class="col-auto">
<span class="avatar avatar-lg">
תמונה
</span>
</div>
<div class="col ml--2">
<h4 class="card-title mb-1">
<a href="#!">
#Html.DisplayFor(modelItem => prod.ProductName)
</a>
</h4>
<p class="card-text small text-muted mb-1">
אימייל
</p>
</div>
<div class="col-auto">
<form method="post">
<input type="submit" asp-page-handler="Delete" value="Delete" asp-route-id="#prod.Id" data-ajax="true" data-ajax-success="deleteItem(this)" />
</form>
</div>
</div>
</li>
}
Index.cshtml.cs-
public async Task<IActionResult> OnPostDeleteAsync(int id)
{
Product currentProduct = new Product();
foreach (var item in _context.Products)
{
if (item.Id==id)
{
currentProduct = item;
break;
}
}
_context.Products.Remove(currentProduct);
_context.SaveChanges();
return RedirectToPage("./Index");
}
Based on your code, we can find that it will return HTTP 302 redirect response status code while you make AJAX request from client side. Please note that AJAX can not automatically redirect to that page, normally we do not return a redirect response to AJAX client.
As #schwartz721 mentioned, if possible, you can try to modify the handler to return JsonResult or OkResult etc rather than RedirectToPage, then you can handle response in success callback.
Besides, if you indeed want to do AJAX submission and redirect user to index page after user delete a product, you may need to do redirection on client side, like below.
window.location.href = url_here;

Dropdown list is not working in the Asp.net Blazor Component

I am trying to learn the new feature in ASP.NET Blazor. I am using Visual Studio 2019. I am trying to create an Ideas Registration form. So the code for dropdownlist i had took from Bootstrap 4. It was not working as expected. Can you please tell me where i am working wrong?
Just a little overwhelmed here, any advice would be much appreciated.
Given Code:
<!-- Card Body -->
<div class="card-body">
<!-- <form -->
<form>
<div class="form-group">
<label for="exampleFormControlInput1">Title</label>
<input type="email" class="form-control" id="exampleFormControlInput1">
</div>
<div class="form-group">
<label for="exampleFormControlSelect1">Description</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="4"></textarea>
</div>
<!-- Basic dropdown -->
<div class="form-group">
<button class="btn btn-primary dropdown-toggle mr-4" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
Basic dropdown
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">.Net</a>
<a class="dropdown-item" href="#">Python</a>
<a class="dropdown-item" href="#">Data Science</a>
<div class="dropdown-divider"></div>
</div>
</div>
<!-- Basic dropdown -->
where i am working wrong
According to the official docs](https://getbootstrap.com/docs/4.0/components/dropdowns/#data-toggledropdown-still-required):
Regardless of whether you call your dropdown via JavaScript or instead use the data-api, data-toggle="dropdown" is always required to be present on the dropdown’s trigger element.
I would suggest you should wrap your Basic dropdown in the following structure
<div class="dropdown">
<button data-toggle="dropdown" class="..." > ...</button>
<div class="dropdown-menu ...>
...
</div>
</div>
You didn't add an event handler for selection. At least you should add a #onclick for the toggle button. When clicking this button, show or hide the dropdown-menu.
Finally, if you want to implement the dropdown component with Blazor(without javascript), you should also replace the text content within the toggle button when someone selects a dropdown list item.
A Demo : How to Create A General Dropdown Component
Rather than simply fixing the issue, I think it's much better to create a general dropdown Component so that we can always invoke them in following way:
#{ var list = new List<string>{ ".NET", "Python","Java" }; }
<Dropdown TItem="string" OnSelected="#OnSelected" >
<InitialTip>This is a dropdown list</InitialTip>
<ChildContent>
<DropdownListItem Item="#list[0]">.NET</DropdownListItem>
<DropdownListItem Item="#list[1]">Python</DropdownListItem>
<div class="dropdown-divider"></div>
<DropdownListItem Item="#list[2]">Java</DropdownListItem>
</ChildContent>
</Dropdown>
#code {
private void OnSelected(string selection)
{
Console.WriteLine(selection);
}
}
Here the TItem is a generic type parameter that is the type of each dropdown list item and can be any .NET type.
Demo
How-To
Add a Shared/Dropdown.razor component:
#using Microsoft.AspNetCore.Components.Web
#typeparam TItem
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle mr-4" data-toggle="dropdown" type="button" #onclick="e => this.show=!this.show "
aria-haspopup="true" aria-expanded="false">
#Tip
</button>
<CascadingValue name="Dropdown" Value="#this">
<div class="dropdown-menu #(show? "show":"")" >
#ChildContent
</div>
</CascadingValue>
</div>
#code {
[Parameter]
public RenderFragment InitialTip{get;set;}
[Parameter]
public RenderFragment ChildContent{get;set;}
[Parameter]
public EventCallback<TItem> OnSelected {get;set;}
private bool show = false;
private RenderFragment Tip ;
protected override void OnInitialized(){ this.Tip = InitialTip; }
public async Task HandleSelect(TItem item, RenderFragment<TItem> contentFragment)
{
this.Tip= contentFragment.Invoke(item);
this.show=false;
StateHasChanged();
await this.OnSelected.InvokeAsync(item);
}
}
Add a Shared/DropdownListItem.razor component:
#using Microsoft.AspNetCore.Components.Web
#typeparam TItem
<a class="dropdown-item" Item="#Item" #onclick="e=> Dropdown.HandleSelect(Item, ChildContent)" >#ChildContent(Item)</a>
#code {
[CascadingParameter(Name="Dropdown")]
public Dropdown<TItem> Dropdown {get;set;}
[Parameter]
public TItem Item{get;set;}
[Parameter]
public RenderFragment<TItem> ChildContent {get;set;}
}
Keep in mind that bootstrap dropdown requires bootstrap javascript to be referenced. And the Blazor template doesn't reference it by default.
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
The accepted answer is great. However, as many have pointed out, the dropdown does not close if an option is not selected. The suggestion to create an #unblur event does not solve the case, as #unclick and #unblur do not seem to work together in .NET 5 (I read somewhere that it does works in the new .NET 6) - #unblur prevents #unclick to be triggered.
I found this solution (#onblur prevents #onclick in blazor server side app), changing the #onclick to #onmousedown and then creating the #onblur event (as suggested) has fixed the issue for me.

ASP.NET Core 2.2. Razor Pages - How to populate a form control based on another field

I have a form control "ConnectorType" which I turned into a dropdown list with pre-defined values (just 3qty currently)
When the user selects and item from this dropdown list, depending on the value selected I then want to populate another text box form control underneath.
To better explain, please see image below:
Example, if TCP Server IN is selected then the form control underneath (textbox)should automatically say "Inbound"
Ideally this text box should also have an attribute/configuration that prevents the user from entering their own text, grayed out perhaps. Once the create form is submitted, the textbox that contains this value "Inbound" will then be added to the SQL Table using Enitity Framework.
The solution requires that this field dynamically changes each time a new item is selected from the list.
Current code for the drop down list:
Page Model Class:
public IEnumerable<SelectListItem> ConnectorTypeList { get; private set; } // temp
public IActionResult OnGet()
{
// prepare the list in here
ConnectorTypeList = new SelectListItem[]
{
new SelectListItem ("TCP Server IN", "TCP Server IN"),
new SelectListItem ("TCP Server OUT", "TCP Server OUT"),
new SelectListItem ("SMTP Server IN", "SMTP Server IN")
};
return Page();
}
Page View:
<div class="form-group">
<label asp-for="ConnectorModel.ConnectorType" class="control-label"></label>
<select asp-for="ConnectorModel.ConnectorType" class="form-control" asp-items="#Model.ConnectorTypeList"></select>
<span asp-validation-for="ConnectorModel.ConnectorType" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConnectorModel.DataFlow" class="control-label"></label>
<input asp-for="ConnectorModel.DataFlow" class="form-control" />
<span asp-validation-for="ConnectorModel.DataFlow" class="text-danger"></span>
</div>
Note the current form-control I'm wanting to modify is the "ConnectorModel.DataFlow" in the above page view code. At the moment it's just a simple textbox that the user can enter their own choice of text.
I'm going round in circles having read up on page handlers etc. It seems there is a onchange event but unsure how to implement this and somehow link it back to the page model class, run a method then postback the result. I'm not looking for a JQuery script as it seems this should not be required in the newer framework, not sure I just don't want a complicated long solution given I will be using a lot of these throughout the app. Thanks in advance...
The easiest way is to use onchange() on your <select> tag and assign data to input using js.(Add id attribute for <select> and <input> before)
If you would like to prevent the user from entering their own text, just use readonly attribute for you input.
<input asp-for="DataFlow" id="dataFlow" class="form-control" readonly/>
The Sample Page View:
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ConnectorModel.ConnectorType" class="control-label"></label>
<select asp-for="ConnectorModel.ConnectorType" id="connectorTypeList" class="form-control" asp-items="#Model.ConnectorTypeList" onchange="assignData()">
<option>Select ConnectorType</option>
</select>
<span asp-validation-for="ConnectorModel.ConnectorType" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConnectorModel.DataFlow" class="control-label"></label>
<input asp-for="ConnectorModel.DataFlow" id="dataFlow" class="form-control" readonly />
<span asp-validation-for="ConnectorModel.DataFlow" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
#section Scripts{
<script>
function assignData() {
var contentType = $("#connectorTypeList").val();
if (contentType == "TCP Server IN") {
$("#dataFlow").val("Inbound");
}
}
</script>
}

Razor Pages - Run a server side method NOT using post

In Razor pages ASP.NET Core, how do I do a basic onclick event for a button which is of type button?
Do I need to wire up an AJAX GET request to get the below "Resend Code" button to work? There is plenty of chatter about OnPost this and that.. but I don't want to post.
Can't be this hard?
<form method="post">
<div asp-validation-summary="All"></div>
<div class="form-group-item">
<label asp-for="Input.TwoFactorCode"></label>
<input asp-for="Input.TwoFactorCode" class="input" />
<span asp-validation-for="Input.TwoFactorCode"></span>
</div>
<div class="form-group-item">
<label class="margin-0" asp-for="Input.RememberMachine">
<input asp-for="Input.RememberMachine" />
#Html.DisplayNameFor(m => m.Input.RememberMachine)
</label>
</div>
<div>
<button type="button" asp-page-handler="ResendCode" class="btn btn-light">Resend Code</button>
<button type="submit" class="btn btn-secondary">Confirm</button>
</div>
</form>
As it stands, the button won't do anything. You can use JavaScript to intercept the button click and then fire a get request using AJAX (jQuery example below):
$('.btn.btn-light').on('click', function(){
$.get('?handler=ResendCode', data, function(){
...
});
});
You can try changing the button to use formmethod="get":
<button type="submit" formmethod="get" asp-page-handler="ResendCode" class="btn btn-light">Resend Code</button>
Note, this will only work for buttons that have type="submit" or type="image" (other type-values don't cause the form to submit). Also it's an HTML5 attribute.
Reference:
https://html.com/attributes/input-formmethod/
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formmethod
maybe try making your own custom handler methods other than OnPost() and OnGet()

How to pass a dynamicy changed model to Partial view?

I have a list of "workbooks" displayed in a table. Each workbook has a "Share" button next to the workbook's title. When the user clicks on the share button a modal dialog is shown containing a form.
The form allows the user to enter a list of the recipient's emails separated by a comma which is validated on the client-side.
As the dialog is located in a partial view _ShareView.cshtml that allows me to pass a modal WorkbookShareModel that has some fields like WorkbookId and Title. The goal here is to pass the details of each workbook when the user presses the share button (i.e. construct a modal and pass it to the already rendered model).
I am not sure how to pass a model to an already rendered view?
The solution have to be done on the client (i.e. dont involve actions on the server that return the partial view provided the parameters are passed). I want to avoid unnesessary calls to the server - we have all the data on the client regarding a workbook and I need to do a POST when the user types in list of emails.
This is my index.cshtml:
#section BodyFill
{
<div id="shareFormContainer">
#{ await Html.RenderPartialAsync("_ShareView", new WorkbookShareModel());}
</div>
<div class="landing-container">
<div class="workbook-container">
<table class="table">
<tbody>
#foreach (var workbook in Model.Workbooks)
{
string trClassName, linkText;
if (workbook.Metadata.SharedBy == null)
{
trClassName = "saved-workbooks";
linkText = workbook.Name;
} else {
trClassName = "shared-with-me";
linkText = string.Format(
BaseLanguage.SharedWithMeWorkbook,
workbook.Name,
workbook.Metadata.SharedBy,
workbook.Metadata.SharedDate.ToShortDateString()
);
}
<tr class="#trClassName">
<td>#Html.ActionLink(linkText, "Open", "OpenAnalytics", new { id = Model.Id, workbook = workbook.Name })</td>
<td class="last-modified-date" title="Last Modified Date">#workbook.ModifiedDate.ToShortDateString()</td>
<td class="share">
<button title="Share" class="share-button" onclick='showSharingView("#workbook.Name", "#workbook.Id", "#Model.Id")'> </button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
}
#section Scripts
{
<!--Load JQuery 'unobtrusive' validation -->
#await Html.PartialAsync("_ValidationScriptsPartial")
<script type="text/javascript">
// hide the modal as soon as the page loads
$('#shareFormModal').modal("hide");
function showSharingView(title, workbookId, id) {
$('#shareFormModal').modal("show");
// how to pass a WorkbookShareModel to my partial view from here?
}
function hideDialog() {
var form = $("#partialform");
// only hide the dialog if the form is valid
if (form.valid()) {
activateShareButtons();
$('#shareFormModal').modal("hide");
}
}
// Helper method that validates list of emails
function IsEmailValid(emailList, element, parameters) {
var SPLIT_REGEXP = /[,;\s]\s*/;
var EMAIL_REGEXP =
/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+##[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/i;
var emails = emailList.split(SPLIT_REGEXP);
for (var i = emails.length; i--;) {
if (!EMAIL_REGEXP.test(emails[i].trim())) {
return false;
}
}
return true;
}
</script>
}
That is my dialog:
#using DNAAnalysisCore.Resources
#model DNAAnalysisCore.Models.WorkbookShareModel
#* Partial view that contains the 'Share Workbook dialog' modal *#
<!-- Modal -->
<div onclick="activateShareButtons()" class="modal fade" id="shareFormModal" role="dialog">
<div class="modal-dialog modal-md">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Share Workbook - #Model.Title</h4>
</div>
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post, new { #id = "partialform" }))
{
<div class="modal-body">
<label>#BaseLanguage.Share_workbook_Instruction_text</label>
<div class="form-group">
<textarea class="form-control" asp-for="Emails" rows="4" cols="50" placeholder="#BaseLanguage.ShareDialogPlaceholder"></textarea>
<span asp-validation-for="Emails" class="text-danger"></span>
</div>
<input asp-for="Title" />
<input asp-for="Id" />
<input asp-for="WorkbookId"/>
</div>
<div class="modal-footer">
<button onclick="hideDialog()" type="submit" class="btn btn-primary">Share</button>
<button onclick="activateShareButtons()" id="btnCancelDialog" type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
}
</div>
</div>
</div>
There are two solutions to solve your problem :
Option 1 :
Since you have got the parameters(title, workbookId, id) , you can call server side function using AJAX to render the partial view , then replace the DIV contained in the partial view with the updated contents in the callback function of AJAX .
You can click here for code sample .
Option 2 :
Directly update related input/area using Jquery . For example , the input tag helper :
<input asp-for="<Expression Name>">
generates the id and name HTML attributes for the expression name specified in the asp-for attribute. So you can set the value using Jquery like :
$("#Title").val("Title")
Please click here for Tag Helpers in forms in ASP.NET Core
With Option 2 , you need to clear the Emails area firstly after user click the share button ; With Option 1 , you don't need to care that since the HTML will replace entirely .