I'm writing an application using Blazor server side and .Net 5. I want when I write text in the search box it will show results in new divs. However, the search results are not displayed. When I debug the code from service works fine.
#page "/"
#using MovieSearch.Service
#using MovieSearch.Data
#using MovieSearch.Helpness
#inject IOMDbService service
<div class="movie-search">
<div class="search-container">
<form action="/">
<input type="text" placeholder="Find a movie" #bind-value="#searchTerm" />
<button type="submit" #onclick="FindMovies"><i class="fa fa-search"></i></button>
</form>
</div>
</div>
<div class="movies">
#if(moviesResult != null)
{
if(!moviesResult.Success)
{
foreach(var error in moviesResult.Errors)
{
<p>#error.Message</p>
}
}
else
{
foreach(var movie in moviesResult.Value)
{
<div class="movie">
<p>#movie.Title</p>
<img src="#movie.Poster" />
</div>
}
}
}
</div>
#code
{
private string searchTerm;
private Result<IEnumerable<Movie>> moviesResult;
async Task FindMovies()
{
moviesResult = await service.FindMovies(searchTerm);
}
}
What can I do to view the results?
Try changing this part of your code from
<form action="/">
<input type="text" placeholder="Find a movie" #bind-value="#searchTerm" />
<button type="submit" #onclick="FindMovies"><i class="fa fa-search"></i></button>
</form>
to just this
<input type="text" placeholder="Find a movie" #bind-value="#searchTerm" />
<button #onclick="FindMovies"><i class="fa fa-search"></i></button>
So in other words, remove the form tags, as well as removing the type on the button. I believe that blazor is now actually trying to post the form to whatever action you specified in the form as opposed to the onclick handler you assigned to your button.
Related
I have a Blazor form using .NET 6 and have it working with an API PUT endpoint that can update the database upon clicking a button. This takes all of the bound input fields in the form and submits them into the payload.
I've modified my endpoint such that if payload is missing any attributes, it sends null and doesn't update the particular database field, essentially ensuring that only the sent changes are the items that get updated.
However, I'm struggling to find an example in Blazor where the submit only sends input fields on the form that were modified. I'm new to Blazor and my original implementation just had a button that had an #onclick event, which then called the endpoint, passing the object that has data bound in the form. This works but I'd prefer that I understand how to only send the data modified to not have unrequired overwrites.
Here's a mockup of what I have (truncated for readability):
#inject IDataSetService DataSetService
#page "/GameData/Data/DataSetEdit"
#page "/GameData/Data/DataSetEdit/{IDRouteParam:int}"
<PageTitle>DataSet Edit</PageTitle>
<div class="content-wrapper">
<!-- Main content -->
<section class="content">
<div class="container-fluid">
<!-- Card -->
<div class="card">
<div class="card-header">
</div>
<form>
<div class="card-body">
<div class="form-group">
<label for="ID">ID</label>
<input type="text" class="form-control" id="ID" placeholder="12345" value="#dataSet.ID">
</div>
<div class="form-group">
<label for="IsActive">Is Active?</label>
<input type="text" class="form-control" id="IsActive" placeholder="IsActive" #bind-value="dataSet.IsActive">
</div>
<div class="form-group">
<label for="IsDeleted">Is Deleted?</label>
<input type="text" class="form-control" id="IsDeleted" placeholder="IsDeleted" #bind-value="dataSet.IsDeleted">
</div>
<div class="card-footer">
<button type="submit" class="btn btn-info" #onclick="() => UpdateDataSet()">Save</button>
<button type="submit" class="btn btn-danger">Cancel</button>
</div>
</form>
</div>
<!-- /.Card -->
}
</div>
</section>
</div>
#code {
private DataSet? dataSet = null;
private string message = string.Empty;
private bool ActiveChecked = false;
private bool DeletedChecked = false;
[Parameter]
public int IDRouteParam { get; set; }
protected override async Task OnParametersSetAsync()
{
message = "Loading DataSet.. ";
var result = await DataSetService.GetDataSetByID(IDRouteParam);
if (!result.Success)
{
message = result.Message;
}
else
{
dataSet = result.Data;
}
}
async void UpdateDataSet()
{
dataSet= await DataSetService.UpdateDataSet(dataSet);
}
}
I have been reading on changing this to an EditForm along with an OnValidSubmit, but I haven't come across an example that shows how to detect fields that were changed and how to use those to build the payload to send to the API.
I have a simple application in .NET Core MVC, with this simple form. When I try to post the form without refresh whole page only rest the form and got the result of done.
My code trial is:
<form asp-area="" asp-controller="ContactUs" asp-action="UserMessage" data-ajax="true">
<h5>Reach us quickly</h5>
<div class="row">
<span asp-validation-for="UserName" class="text-danger"></span>
<div class="col-sm-6 col-12">
<div class="form-group">
<input asp-for="UserName" class="form-control" name="UserName" placeholder="Enter name" required="required">
</div>
</div>
<span asp-validation-for="Email" class="text-danger"></span>
<div class="col-sm-6 col-12">
<div class="form-group">
<input asp-for="Email" class="form-control" name="Email" placeholder="Enter email" required="required">
</div>
</div>
</div>
<div class="row">
<span asp-validation-for="Msg" class="text-danger"></span>
<div class="col-12">
<div class="form-group">
<textarea asp-for="Msg" name="Msg" class="form-control" rows="7" cols="25" placeholder="Message"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 mt-3">
<button type="submit" class="btn solid-btn" id="btnContactUs">
Send Message
</button>
</div>
</div>
</form>
and my action is:
[HttpPost]
public async Task<IActionResult> UserMessage(ContactUs model)
{
try
{
if (ModelState.IsValid)
{
_context.Add(model);
await _context.SaveChangesAsync();
return NoContent();
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return NoContent();
}
I want to change return NoContent(); so I can show a message to the user that his message has sent or failed, without refreshing the whole page.
Your form tag is missing some other ajax attributes:
<form method="post"
data-ajax="true"
data-ajax-method="post"
data-ajax-url="#Url.Page("UserMessage", "ContactUs")"
data-ajax-loading="#loading"
data-ajax-mode="replace"
data-ajax-update="#updateDiv">
<!-- form controls -->
<button type="submit" class="btn solid-btn" id="btnContactUs">Send Message</button>
<span id="loading" style="display:none;"> <i class="fas fa-spinner fa-spin"></i></span>
</form>
<div id="updateDiv">
<!-- ajax content will load here -->
<!-- you can put the form inside this div -->
<!-- so after submit the result will replace the form controls -->
</div>
<!-- include jquery libraries -->
#section Scripts {
<script src="https://cdn.jsdelivr.net/npm/jquery#3.5.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-ajax-unobtrusive#3.2.6/dist/jquery.unobtrusive-ajax.min.js"></script>
}
The backend method can return the result as below:
public async Task<ContentResult> OnPostUserMessageAsync(ContactUs model)
{
try
{
if (ModelState.IsValid)
{
_context.Add(model);
await _context.SaveChangesAsync();
return Content("done");
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return Content("something went wrong...");
}
See Ajax Request Using Inline Attributes
If you don't want the page to be replaced, you'll have to use ajax to post the data via javascript. Posting a form in a browser will replace the current html with the result of the controller, that's just how forms work.
It is also common practice to redirect any successful POST to a different page, so that the user can refresh that page without processing the POST request twice.
thanks for #Laz Ziya i have used his code and modify form to be
instead of
<form method="post"
data-ajax="true"
data-ajax-method="post"
data-ajax-url="#Url.Page("UserMessage", "ContactUs")"
data-ajax-loading="#loading"
data-ajax-mode="replace"
data-ajax-update="#updateDiv">
to be
<form asp-area="" asp-controller="ContactUs" asp-action="UserMessage" data-ajax-loading="#loading" data-ajax-mode="replace" data-ajax-update="#updateDiv" data-ajax-success="Success" data-ajax-failure="Failure" data-ajax="true">
for post form without refresh ,you need to use ajax in your code.
I have a piece of MVC asp.net C# that uses FineUploader. I used it in PHP before with no issues, but in asp.net c# mvc it fails (it triggers but always posts null) can anyone shed light onto why? I think it's the default transport is imprecise and it's not really using IFormFile but without any documentation from FineUploader it's impossible to know what structure they rely on for transport - regardless the c# controller fires correctly, but has null in it.
Here is the <head> markup
<!-- Fine Uploader Gallery CSS file
====================================================================== -->
<link rel="stylesheet" href="/fine-uploader/fine-uploader-new.css" />
<link rel="stylesheet" href="/fine-uploader/fine-uploader-gallery.css" />
<!-- Fine Uploader JS file
====================================================================== -->
<script src="/fine-uploader/fine-uploader.core.js"></script>
<script src="/fine-uploader/fine-uploader.js"></script>
<!-- Fine Uploader Gallery template
====================================================================== -->
<script type="text/template" id="qq-template-gallery">
<div class="qq-uploader-selector qq-uploader qq-gallery" qq-drop-area-text="Drop files here">
<div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
</div>
<div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
<span class="qq-upload-drop-area-text-selector"></span>
</div>
<div class="qq-upload-button-selector qq-upload-button">
<div>Upload a file</div>
</div>
<span class="qq-drop-processing-selector qq-drop-processing">
<span>Processing dropped files...</span>
<span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
</span>
<ul class="qq-upload-list-selector qq-upload-list" role="region" aria-live="polite" aria-relevant="additions removals">
<li>
<span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
<div class="qq-progress-bar-container-selector qq-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
<span class="qq-upload-spinner-selector qq-upload-spinner"></span>
<div class="qq-thumbnail-wrapper">
<img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale>
</div>
<button type="button" class="qq-upload-cancel-selector qq-upload-cancel">X</button>
<button type="button" class="qq-upload-retry-selector qq-upload-retry">
<span class="qq-btn qq-retry-icon" aria-label="Retry"></span>
Retry
</button>
<div class="qq-file-info">
<div class="qq-file-name">
<span class="qq-upload-file-selector qq-upload-file"></span>
<span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
</div>
<input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
<span class="qq-upload-size-selector qq-upload-size"></span>
<button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">
<span class="qq-btn qq-delete-icon" aria-label="Delete"></span>
</button>
<button type="button" class="qq-btn qq-upload-pause-selector qq-upload-pause">
<span class="qq-btn qq-pause-icon" aria-label="Pause"></span>
</button>
<button type="button" class="qq-btn qq-upload-continue-selector qq-upload-continue">
<span class="qq-btn qq-continue-icon" aria-label="Continue"></span>
</button>
</div>
</li>
</ul>
<dialog class="qq-alert-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Close</button>
</div>
</dialog>
<dialog class="qq-confirm-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">No</button>
<button type="button" class="qq-ok-button-selector">Yes</button>
</div>
</dialog>
<dialog class="qq-prompt-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<input type="text">
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Cancel</button>
<button type="button" class="qq-ok-button-selector">Ok</button>
</div>
</dialog>
</div>
</script>
Here is the <body> markup
<!-- Fine Uploader DOM Element
====================================================================== -->
<div id="fine-uploader-gallery"></div>
<!-- Your code to create an instance of Fine Uploader and bind to the DOM/template
====================================================================== -->
<script>
var galleryUploader = new qq.FineUploader({
element: document.getElementById("fine-uploader-gallery"),
template: 'qq-template-gallery',
request: {
endpoint: '#Url.Action("UploadFile", "Home")'
},
thumbnails: {
placeholders: {
waitingPath: '/fine-uploader/waiting-generic.png',
notAvailablePath: '/fine-uploader/not_available-generic.png'
}
},
validation: {
allowedExtensions: ['jpeg', 'jpg', 'gif', 'png']
}
});
</script>
Here is the HomeController.cs controller
[HttpPost]
public IActionResult UploadFile(IFormFile file)
{
if (file != null)
{
using (var reader = new StreamReader(file.OpenReadStream()))
{
string contentAsString = reader.ReadToEnd();
byte[] contentAsByteArray = GetBytes(contentAsString);
return File(contentAsByteArray, file.ContentType);
}
}
return null;
}
I know it fires the server because when I upload three items the controller fires 3 times. But all null.
incidentally, for bonus points, I am also always getting the following console errors even though the files paths are correct
By default, Fine Uploader will send the file in the body of a multipart encoded POST request. You can use Request object instead of method parameters.
The server should return valid JSON response to all requests.
[HttpPost]
public ActionResult UploadFiles()
{
string path = Server.MapPath("~/Uploads/");
var fileExists = Request.Files.Count > 0;
if (fileExists)
{
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
try
{
HttpPostedFileBase fileBase = Request.Files[0];
if (fileBase != null)
{
string fileName = Path.GetFileName(fileBase.FileName);
fileBase.SaveAs(path + fileName);
}
return Json(new { success = "true"});
}
catch (Exception ex)
{
return Json(new { success = "false", error = ex.Message });
}
}
return Json(new { success = "false"});
}
With Razor Pages what is the best way to handle this situation where I'd like to have a user click a button within a table and then have a task which uses elements passed from the row for an action?
So far I have this table loaded with a data model and I'd like them to click a row and use that row in my action:
Data Model:
public struct CollapseReportModel
{
public HighLevelOutput Summary { get; set; }
public IEnumerable<HighLevelOutput> WeeksOfData { get; set; }
}
Table:
<div class="container">
<div id="accordion">
#{int counter = 0; }
#foreach (var dataVM in Model.CollapseReport)
{
<div class="card">
<div class="card-header" id="heading#(counter)">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapse#(counter)" aria-expanded="true" aria-controls="collapse#(counter)">
#dataVM.ToString()
</button>
</h5>
</div>
<div id="collapse#(counter)" class="collapse" aria-labelledby="heading#(counter)" data-parent="#accordion">
<div class="card-body">
I'm trying to use this button click to send data to a task but it just passes null values:
<form method="post">
<input type="submit" class="btn btn-default" value="Add to Log" asp-page-handler="AddLog" asp-route-data="#dataVM.Summary.CorpCustomer, #dataVM.Summary.Item)" />
</form>
<ul class="list-group">
#foreach (var item in dataVM.WeeksOfData)
{
<li class="list-group-item">#($"{item.Item}, {item.ItemDescription}, {item.CorpCustomer}, {item.SummedOrder}, {item.SummedForecast}, {item.Difference}, {item.Week}")</li>
}
</ul>
</div>
</div>
</div>
counter++;
}
</div>
</div>
<script src="~/jquery.js"></script>
<script src="~/bootstrap.js"></script>
To this handler:
public Task<IActionResult> OnPostAddLog(string var1, string var2)
{
//Use elements from the row to perform an action
var test = var1;
var t2 = var2;
return null;
}
Just add inputs to your form so they will be posted to your action.
<form method="post">
<input type="hidden" name="var1" value="#dataVM.WhateverProperty1" />
<input type="hidden" name="var2" value="#dataVM.WhateverProperty2" />
<input type="submit" class="btn btn-default" value="Add to Log" asp-page-handler="AddLog" asp-route-data="#dataVM.Summary.CorpCustomer, #dataVM.Summary.Item)" />
</form>
Be sure to match the input name to the parameter name in your action.
Also, decorate your OnPostAddLog method with [HttpPost] as your form use POST method.
I'm trying to setup a shopping cart for my project.
I am storing the item name, price, and description into Session and call it back and eventually use it for payment processing.
I've written everything and am now having this weird error where it says
"} expected" in the error list.
Also, when I hover over #using in #using (Html.BeginForm("ValidateForm", "PayPal")),
it says "The using block is missing a } character".
I just don't know what the problem is.
Any help would be greatly appreciated.
Thank you.
#{
ViewBag.Title = "ShoppingCart";
}
<h2>ShoppingCart</h2>
#using (Html.BeginForm("ValidateCommand", "PayPal"))
{
var cart = Session["Cart"];
<div class="row">
<div class="col-lg-9">
<h2><strong>Courses</strong></h2><br />
#foreach (var item in cart)
{
<div class="col-md-4 col-xs-6 col-s-8 col-lg-4">
<img src="~/Images/party.gif" style="width: 175px" class="img-responsive" />
<h2>#item.className</h2>
<input type="text" name="product" value="#item.className" hidden="hidden" />
<input type="text" name="totalPrice" value="#item.classPrice" hidden="hidden" />
<input type="text" name="custom" value="#item.ClassID" hidden="hidden" />
}
<br />
</div>
</div>
<input class="btn btn-default" type="submit" name="btnConfirm" value="Check Out with Paypal" />
</div>
}
Your div and /div tags appear to be mis-matched, Razor views care about that sort of thing, make sure you open and close them inside the same code block (defined by curly braces)
You have a "dangling-div". Here:
}
<br />
</div>
That </div> should be inside the foreach brace.