I have two views as shown below:
boott.cshtml
#model model
<div>
#if (Model.ViewModel != null)
{
#Html.Partial("_b_table", Model)
}
<span class="d2-fldr">Enter folder name: </span>
<input type="text" name="txtName" class="txtFldrname"/>
<a class="small d2-createfldr" title="Create folder" href="#">
<span class="glyphicon glyphicon-plus d2-ico"></span>
<span class="d2-axn">Create folder</span>
</a>
)
</div>
_boott_table.cshtml
#model model
<div class="#BOOTSTRAP.ROW">
-- some content from model
</div>
The view boott.cshtml is directly rendered from the controller's action "boott".
The partial view _boott_table.cshtml content changes always based on the option we select in partial view.
When we click on the options in partial view, we are calling the same action method "boott" and renders the partial boott.cshtml and send the html back.
However there is some static content in boott.cshtml (spans, input, a tag), they are not part of partial view _boott_table.cshtml and should not get re-rendered when ever we click on the options in _boott_table.cshtml.
How can we handle this situation ?
can somebody advise?/
Related
I am trying to navigate the user to a new page with a button click. I am having issues with rendering the new view. Any time I do click on the button, I either get an error for a dropdown on my page, or I get the home page view but with my desired route in the URL. I wanted to note that the user will be navigating to this page from the home page, which I made into my new landing page on the app. I wanted to point that out in case something I did here can be modified.
How I created a new landing page
I want to navigate from my landing page to my book inventory page.
My View (On the landing page):
<form method="post" asp-controller="Home" asp-action="Home" role="post">
<div class="form-group">
<label asp-for="bookName"></label>
<select name="bookName" asp-items="#(new SelectList(ViewBag.message, "ID", "bookName"))">
</select>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
<div class="row">
<div class="form-group">
<a asp-controller="BookInventory" asp-action="Index">
<input type="button" value="Book Inventory Page" />
</a>
</div>
</div>
My Controller (On my landing page)
public void GetBooksDDL()
{
List<BookModel> bookName = new List<BookModel>();
bookName = (from b in _context.BookModel select b).ToList();
bookName.Insert(0, new BookModel { ID = 0, bookName = "" });
ViewBag.message = bookName;
}
[HttpGet("[action]")]
[Route("/Home")]
public IActionResult Home()
{
GetBooksDDL()
return View();
}
My Controller (On my book inventory page):
[HttpGet("[action]")]
[Route("/Index")]
public IActionResult Index()
{
return View();
}
I wanted to note that my breakpoint on my book inventory controller does hit the 'return View()', but it will still render the items from the homepage.
The error I get with the book dropdown says:
ArgumentNullException: Value cannot be null. (Parameter 'items')
Microsoft.AspNetCore.Mvc.Rendering.MultiSelectList.ctor(IEnumerable items, string dataValueField, string dataTextField, IEnumerable selectedValues, string dataGroupField).
I'm wondering why I'm getting this error when I'm trying to navigate to a different page. Since this is the new landing page, is it possible that it is passing along all of its data to the rest of the pages?
ArgumentNullException: Value cannot be null. (Parameter 'items')
Microsoft.AspNetCore.Mvc.Rendering.MultiSelectList.ctor(IEnumerable
items, string dataValueField, string dataTextField, IEnumerable
selectedValues, string dataGroupField).
About this error, it means that you didn't set the value for the select element, before return to the view, please check the ViewBag.message value, make sure it contains value.
Note: Please remember to check the post method, if the Http Get and Post method returns the same page, make sure you set the ViewBag.message value in both of the action methods.
I wanted to note that my breakpoint on my book inventory controller
does hit the 'return View()', but it will still render the items from
the homepage.
In the BookInventory Controller Index action method, right click and click the "Go to View" option, make sure you have added the Index view.
Based on your code, I have created a sample using the following code, it seems that everything works well.
Code in the Home Controller:
[HttpGet("[action]")]
[Route("/Home")]
public IActionResult Home()
{
GetBooksDDL();
return View();
}
[HttpPost("[action]")]
[Route("/Home")]
public IActionResult Home(BookModel book, string bookName)
{
GetBooksDDL();
//used to set the default selected value, based on the book id (bookName) to find the book.
List<BookModel> booklist = (List<BookModel>)ViewBag.message;
book = booklist.Find(c => c.ID == Convert.ToInt32(bookName));
return View(book);
}
Code in the Home view:
#model BookModel
#{
ViewData["Title"] = "Home";
}
<h1>Home</h1>
<form method="post" asp-controller="Home" asp-action="Home" role="post">
<div class="form-group">
<label asp-for="bookName"></label>
<select name="bookName" asp-items="#(new SelectList(ViewBag.message, "ID", "bookName", Model == null? 0:Model.ID))">
</select>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
<div class="row">
<div class="form-group">
<a asp-controller="BookInventory" asp-action="Index">
<input type="button" value="Book Inventory Page" />
</a>
</div>
</div>
Code in the BookInventory controller:
public class BookInventoryController : Controller
{
[HttpGet("[action]")]
[Route("/Index")]
// GET: BookInventory
public ActionResult Index()
{
return View();
}
The screenshot as below:
If still not working, please check your routing configuration, perhaps there have some issue in the routing configure.
Your anchor tag formation is incorrect. You cannot write a button within anchor tag.
Do something like this:
<a asp-action="Index" asp-controller="BookInventory" class="btn btn-primary">Book Inventory Page</a>
Here the class will help your anchor tag look like buttons. I hope you have used bootstrap in your project. If not, then use it.
Hope this helps.
Here is another simple way:
<button type="button" class="btn" onclick="window.location.href = '/YourPage'">Button Title</button>
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.
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 .
I have an anchor which should replace a grid with a partial view .
<a class="btn btn-primary"
data-ajax="true"
data-ajax-method="GET"
data-ajax-mode="replace"
data-ajax-update="content"
data-ajax-url="#Url.Action("add","user")"> Create User </a>
<div class="row table-area">
<div class="col-md-12" id="content">
#Html.AjaxGrid(Url.Action("results", "user"))
</div>
</div>
I see it calls the user action with partial view but it never updates the section with id="content".
Here is my controller method -
[Route("add")]
public IActionResult AddUser()
{
return PartialView("Partials/AddUser",new RegisterViewModel());
}
Ideally it should replace the grid content with the partial view altogether but it is not replacing . The response status is 200 and I can see that the contents are being returned in response . Anybody has any idea what is the issue here ?
Change data-ajax-update="content" to data-ajax-update="#content"
Rather than using data-ajax-url, use the asp-controller and asp-action and the #content should work.
<a class="btn btn-primary" asp-controller="user" asp-action="add"
data-ajax="true"
data-ajax-method="GET"
data-ajax-mode="replace"
data-ajax-update="#content">Create User</a>
I need:
Acess /Client/Create
Add dynamically Partial Views (/Product/Card) and bind them to Client.Products
In each Partial View when i click in a button open a bootstrap modal windows where i can set Product's information
Close the modal and reflect changes of modal reflect in the Card's Product.
The problem is: how to change product informations in another view(other than Card) and reflect to the product of the card?
#using (Html.BeginCollectionItem("Products"))
{
#Html.HiddenFor(model => model.ClientID)
#Html.HiddenFor(model => model.ProductID)
<div class="card">
<img class="card-img-top" src="http://macbook.nl/wp-content/themes/macbook/images/png/iphone318x180.png" alt="Grupo Logo">
<div class="card-block">
<h4 class="card-title">#Model.Name</h4>
<p class="card-text">#Model.Desc</p>
<div class="btn-group">
<button type ="button" class="btn btn-primary open-modal" data-path="/Product/Edit/#Model.ProductID">Edit</button>
<button type="button" class="btn btn-primary open-modal" data-path="/Product/Features/#Model.ProductID">Features</button>
</div>
</div>
</div>
}
You can do this is another view (or by dynamically loading another view into a modal. The object has not been created yet, and since you using BeginCollectionItem() to generate new items, any other view you used would not be using the same Guid created by that helper so you would not be able to match up the collection items.
Instead, include the 'other' properties within the partial, but put them in a hidden element that gets displayed as a modal when you click the buttons.
The basic structure of the partial for adding/editing a Product would be
<div class="product">
#using (Html.BeginCollectionItem("Products"))
{
#Html.HiddenFor(m => m.ClientID)
#Html.HiddenFor(m => m.ProductID)
<div class="card">
....
<button type ="button" class="btn btn-primary edit">Edit</button>
</div>
// Modal for editing additional data
<div class="modal">
#Html.TxtBoxFor(m => m.SomeProperty)
#Html.TxtBoxFor(m => m.AnotherProperty)
....
</div>
}
</div>
And then handle the buttons .click() event (using delegation since the partials will be dynamically added to the view) to display the associated modal (assumes you have a <div id="products"> element that is the container for all Products)
$('#products').on('click', '.edit', function() {
var modal = $(this).closest('.product').find('.modal');
modal.show(); // display the modal
});