The goal
Create Shared UI Templates with C# + MVC 4 + Razor Engine.
The problem
I do not know how to do.
Details
I have the follow template:
<li>
<div class="introduction">
<h3>{productName}</h3>
</div>
<div class="presentation">
<img src="{productImage}" alt="" />
</div>
<div class="description">
<p>Starting by</p>
<h3>{minProductPrice}</h3>
<p class="product-unity">/a <span class="product-measure"
data-measure-shortcut="{productMeasureShortname">{productMeasureName}
</span></p>
</div>
<div class="controls">
<button class="button green add" title="Add to comparsion list">+</button>
<div class="tooltip-quantity">
<p class="float-left">Quantity:</p>
<form method="post" action="#">
<input class="quantity float-left" name="product_quantity"
maxlength="2" type="text" />
<span class="float-left">/{productMeasureName}(s)</span>
<button disabled class="button orange filled float-right">
Add
</button>
</form>
</div>
<button class="button light-blue filled compare float-right" title="This product is available in 6 stores">Compare</button>
</div>
</li>
and when I want to call it, I would to do something like this:
#Html.RenderMyTemplate("Product Name", "Product Image", "Min Product Price"...)
Logically, the parameters will replace the placeholders on the template.
Any idea?
Thanks in advance!
You can use partial view:
#Html.Partial("MyView", Model)
Basicaly it renders given file (MyView) using model (Model) as regular razor powered template.
In your case (I used string[] as Model, but you can use whatever you want e.g. IDictionary<string, string>):
#Html.Partial("MyView", new[] { "Product Name", "Product Image", "Min Product Price" })
In view:
#inherits System.Web.Mvc.WebViewPage<string[]>
<li>#Model[0]</li>
UPDATE (with dictionary)
#Html.Partial("MyView", new Dictionary<string, object> { { "name", "Product1"}, { "price", 100 } })
then
#inherits System.Web.Mvc.WebViewPage<Dictionary<string, object>>
<li>#Model["name"]</li>
Related
#for (var i = 1; i < 5; i++)
{
var Tier = $"Tier{i}Score";
<div class="col-12 mt-2">
<div class="row">
<div class="col-2">
<label>#i</label>
</div>
<div class="col-md col-6">
<div class="d-flex align-items-baseline">
<label>#localizer[$"Label_Tier{i}Description"]</label>
<i class="fas fa-info-circle pl-2 cursor-pointer tooltip-ico" data-toggle="tooltip" data-placement="right" title="#localizer[$"Tooltip_Tier{i}Score"]"></i>
</div>
</div>
<div class="col-md col-4">
<input asp-for="#Tier" type="text" class="line-input form-control" maxlength="4" autocomplete="off" />
</div>
</div>
</div>
}
When my div is generated, my id just display as id=Tier, I would like to get result id=Tier1Score, id=Tier2Score, id=Tier3Score and id=Tier4Score. How I can achieve this. Thank you.
You can't also see this answer: Dynamically assigning asp-for variables
But since it's just a TagHelper (it doesn't do anything besides writing correct HTML) you could also write it like this:
<input name="#Tier" id="#Tier" type="text" class="line-input form-control" maxlength="4" autocomplete="off" />
The name is important for the form-post, the id is probably used for javascript thingies you might want to do.
I have a problem with implement saving value with input type number to the database. I have created website with ASP .NET MVC with UnitOfWork and Repositories. I have a Commodity model, where I have field Amount, and I have HomeViewModel in which I have a field Amount also. I would like to overwrite the amount field from the commodity model. Should I use onchange or onclick in input or a tags in html code, or all with my basic ideas are nonsens ?
Below is the code snippet with view created in RazorPages with extension .cshtml.
<div class="col-12">
<div class="row my-3">
#foreach(var Commodity in Model.CommodityList.Where(c=>c.CategoryId==category.Id))
{
<div class="col-lg-4 col-xl-3 col-md-6 pb-4">
<div class="card" style="border:2px solid #43ac6a;border-radius:5px;
backgroundcolor: #fffeee">
<div class="pl-3 pt-1 text-center">
<h3 class="card-title text-primary"><b>#Commodity.Name</b></h3>
</div>
<div class="d-flex justify-content-between">
<div class="pl-1 text-muted">#localizer.Get("Price")</div>
<div class="pr-1 text-danger h5">$#Commodity.Price</div>
</div>
<img src="#Commodity.ImageUrl" class="card-img-top p-2 rounded" />
<div class="col-9">
<input onchange="save()" asp-for="#Commodity.Amount" type="number"
id="quantity" name="quantity" min="0" max="100" />
</div>
<a onclick="save()" asp-action="Details" class="btn btn-success"
style="border-
radius:2px;" asp-route-id="#Commodity.Id"
onclick="save()">#localizer.Get("Details")</a>
</div>
</div>
}
</div>
</div>
My problem is that I can't write the value from after pressing the button below as the tag.
Below is the method written by me in controller regarding to the view
public IActionResult Index()
{
HomeVM = new HomeViewModel()
{
CategoryList = _unitOfWork.Category.GetAll(),
CommodityList = _unitOfWork.Commodity.GetAll(includeProperties: "Category"),
ServiceList = _unitOfWork.Service.GetAll(includeProperties: "Category,Payment"),
EmployeeList = _unitOfWork.Employee.GetAll(includeProperties: "Service"),
Amount = _unitOfWork.Commodity.GetFirstOrDefault(includeProperties:
"Category").Amount
};
foreach (var commodity in (_unitOfWork.Commodity.GetAll(includeProperties:
"Category")))
{
var CommodityFromDb = commodity;
CommodityFromDb.Amount = HomeVM.Amount;
_unitOfWork.Save();
}
_unitOfWork.Save();
return View(HomeVM);
}
I have a guess that you probably need to do it somehow with jquery, in a file with the extension js, but I have no idea how. I would be grateful for any help.
I have created a search input for my website that is attached to a dropdown menu. But I need to populate the items in the dropdown menu with items from a html helper select list which is essential for the search function. Is it possible to render the items of the search list in a bootstrap dropdown menu that is posted to a controller?
HTML Search Function
<div class="col-lg-6">
#{using (Html.BeginForm("Results", "Searchv2", FormMethod.Get)) {
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Action <span class="caret"></span></button>
<ul class="dropdown-menu">
#Html.DropDownList("Searchby", new SelectList(new[] { "User", "Restaurant", "Cuisine" }))
</ul>
</div>
<input type="text" class="form-control" placeholder="Search" name="SearchString" id="SearchString">
</div>
}}
</div>
Use the conventional hyperlink tags in the bootstrap dropdown-menu:
<ul class="dropdown-menu">
#foreach (var searchType in new[] { "User", "Restaurant", "Cuisine" })
{
<li>#searchType</li>
}
</ul>
Then use JQuery to set a hidden input value when these hyperlinks are selected:
<input type="hidden" name="SearchBy" />
<script>
$(".dropdown-menu a").click(function() {
$("input[name='SearchBy']").val($(this).html());
});
</script>
i have a grid view to show my blog posts, my posts are in video,image,text format and each has html template that is different with another:
html:
<!-- Image Format -->
<div class="post format-image box">
<div class="frame">
<a href="post.html">
<img src="Templates/images/art/post1.jpg" alt="" />
</a>
</div>
<h2 class="title">Morning Glory</h2>
<p>text</p>
<div class="details">
<span class="icon-image">September 26, 2012</span>
<span class="likes">44</span>
<span class="comments">3</span>
</div>
</div>
<!-- Video Format -->
<div class="post format-video box">
<div class="video frame">
<iframe src="http://player.vimeo.com/video/40558553?title=0&byline=0&portrait=0" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
</div>
<h2 class="title">Fragments of Iceland</h2>
<p>text</p>
<div class="details">
<span class="icon-video">September 13, 2012</span>
<span class="likes">18</span>
<span class="comments">1</span>
</div>
</div>
<!-- Text Format -->
<div class="post format-standard box">
<h2 class="title">The Meridian Sun</h2>
<p>text</p>
<p>text</p>
<div class="details">
<span class="icon-standard">August 13, 2012</span>
<span class="likes">11</span>
<span class="comments">0</span>
</div>
</div>
as you know if i want to have list of my posts in usually way
i should add grid view with item template and set my template in it,
but as you see i have 3 templates for my records,
and i have a field in my table called 'PostMode' that accepts 3 string :
Video, Image, Text.
now my question is how can i use 3 templates in item template that if my record was
Video display video template and if it was Text display Text format in my blogs list.
TemplateField tF = new TemplateField();
// tF.HeaderText = dr["COLUMN_NAME"].ToString();
tF.HeaderText = col.ToString();
tF.ItemTemplate = LoadTemplate("~/xxxxxxx.ascx");
grdVw.Columns.Add(tF);
Sorry for posting in such a hurry ,
Hope it helps .
The Goal
Make a dynamic list of products.
The Scenario
I have a shopping application with products. When I click on the add button of a product, I want to display in the sidebar, the product what I have added.
Summarized Problem (You just need to read this)
I have the following code in my ProductsSummary/Index.cshtml (using Razor Engine):
<ul class="summary">
#if (Session["ProductsSummary"] == null)
{
<li class="is-empty">
<p>Your summary is empty.</p>
</li>
<li data-bind="attr: { 'data-product-id': id }">
<div class="product-summary-actions float-right">
<button class="btn btn-danger btn-mini remove-item">
<i class="icon-remove"></i>
</button>
</div>
<div class="product-summary-quantity">
<h6 data-bind="text: infoComposition"></h6>
</div>
<div class="product-summary-description">
<p data-bind="text: name"></p>
</div>
</li>
}
else
{
foreach
(var product in
(List<MyApp.Models.Data.getSpecificProductToShoppingList_Result>)
Session["ProductsSummary"])
{
<!-- ko foreach: products -->
<li data-product-id="#product.id">
<div class="product-summary-actions float-right">
<button class="btn btn-danger btn-mini remove-item">
<i class="icon-remove"></i>
</button>
</div>
<div class="product-summary-quantity">
<h6>
#product.quantity
#product.measure#(#product.quantity == 1 ? "" : "s")
</h6>
</div>
<div class="product-summary-description">
<p>#product.name</p>
</div>
</li>
<!-- /ko -->
}
}
</ul>
As you can see, there is three <li> on the code. The first is to display a message with "The summary is empty." case the session is null (and of course, the Session is null case any product has been added); the second li serves as model for Knockout when I add something when the session is null; and the last one is to display the products what are in the session.
I'm feeling a little "DRY" right here. How can I reuse the same template regardless of whether session exists or not?
Detailed Problem
I have the following code in my ProductsSummary/Index.cshtml (using Razor Engine):
<ul class="summary">
#if (Session["ProductsSummary"] == null)
{
<li class="is-empty">
<p>Your summary is empty.</p>
</li>
<li data-bind="attr: { 'data-product-id': id }">
<div class="product-summary-actions float-right">
<button class="btn btn-danger btn-mini">
<i class="icon-remove"></i>
</button>
</div>
<div class="product-summary-quantity">
<h6 data-bind="text: infoComposition"></h6>
</div>
<div class="product-summary-description">
<p data-bind="text: name"></p>
</div>
</li>
}
else
{
foreach
(var product in
(List<MyApp.Models.Data.getSpecificProductToShoppingList_Result>)
Session["ProductsSummary"])
{
<!-- ko foreach: products -->
<li data-product-id="#product.id">
<div class="product-summary-actions float-right">
<button class="btn btn-danger btn-mini remove-item">
<i class="icon-remove"></i>
</button>
</div>
<div class="product-summary-quantity">
<h6>
#product.quantity
#product.measure#(#product.quantity == 1 ? "" : "s")
</h6>
</div>
<div class="product-summary-description">
<p>#product.name</p>
</div>
</li>
<!-- ko -->
}
}
</ul>
As you can see, there is an if that checks if ProductsSummary session exists. If yes, then the application displays on the screen a list of products that I added on my summary.
Case the session is null, as you can see, the application displays the message within the li with is-empty class.
The point is: I really need of the "template" after <li class="is-empty">[...]</li> to display an item that was added to the summary?
I mean, I know that Knockout needs something to display when I click the "Add Product" button regardless of whether or not there is a session, but I'm repeating the same template for similar purposes.
Look to this fragment:
<li data-product-id="#product.id">
<div class="product-summary-actions float-right">
<button class="btn btn-danger btn-mini remove-item">
<i class="icon-remove"></i>
</button>
</div>
<div class="product-summary-quantity">
<h6>
#product.quantity
#product.measure#(#product.quantity == 1 ? "" : "s")
</h6>
</div>
<div class="product-summary-description">
<p>#product.name</p>
</div>
</li>
In this case, I'm using it within foreach because I must to display the items fetched from the database.
On the other hand, the following fragment exists if there isn't a session:
<li data-bind="attr: { 'data-product-id': id }">
<div class="product-summary-actions float-right">
<button class="btn btn-danger btn-mini">
<i class="icon-remove"></i>
</button>
</div>
<div class="product-summary-quantity">
<h6 data-bind="text: infoComposition"></h6>
</div>
<div class="product-summary-description">
<p data-bind="text: name"></p>
</div>
</li>
As you can see, the both fragments are similar — one represents the data from database, and the other represents a model to work with Knockout when there is no session, respectively — and I need a way to "templatize" this.
What I Really Need
Someone enters in my site/application;
At the right side of my layout there is a sidebar with a message: "The summary is empty.";
"Oh, what a nice product! I will add it to my summary!", then the user clicks on Add button, the "The summary is empty." message disappears and the product added by user appears in the format of an item from a list (the same template that I have passed before [first/second fragment]).
"Ok, I will to another category of products now." — *The user clicks on "TVs" category* — "OH MY GOD! Look at this TV! I will add to my summary right now!" — *The user clicks on "Add Button" of a random TV.* — Already had a product in the list, but another (the TV) appears.
"Oh, nevermind. I do not have money. I will remove these items from my summary." — *The user clicks on "remove button" of each product on the summary* — And without products, the summary displays: "The summary is empty." just like a magic, without any refresh or something like this.
(Funny, huh?)
The KnockoutJS Script
$(document).ready(function () {
function Product(id, name, measure, quantity) {
this.id = ko.observable(id);
this.name = ko.observable(name);
this.measure = ko.computed(function () {
return quantity > 1 ? measure + "s" : measure;
}, this);
this.quantity = ko.observable(quantity);
this.infoComposition = ko.computed(function () {
return this.quantity() + " " + this.measure()
}, this);
}
function SummaryViewModel() {
this.products = ko.observableArray([]);
this.addToSummary = function (formElement) {
var $productId = $(formElement).children("[name=productId]").val();
var match = $(".summary")
.find("li[data-product-id=" + $productId + "]").length;
if (!match) {
var $productName =
$(formElement).children("[name=productName]").val(),
$productMeasure =
$(formElement).children("[name=productMeasure]").val(),
$productQuantity =
$(formElement).children("[name=productQuantity]").val();
this.products.push
(new Product
($productId,
$productName,
$productMeasure,
$productQuantity));
$.ajax({
type: "POST",
url: "/ProductsSummary/Add",
data:
{
productId: $productId,
productQuantity: $productQuantity
}
});
}
}
};
var summaryViewModel = new SummaryViewModel();
ko.applyBindings(summaryViewModel);
$("body").on("click", ".remove-item", function () {
summaryViewModel.products.remove(ko.dataFor(this));
$.ajax({
type: "POST",
url: "/ProductsSummary/Remove",
data: { productId: $(this).closest("li").data("product-id") }
});
});
});
What is happening, eventually?
What I'm doing works and does not work. Technically, my code works, but I wouldn't to repeat it. Is it possible?
Technical Details
The server-side team is with C#.NET with MVC 4 and Razor Engine and the client-side team is KnockoutJS and jQuery.
For the empty cart message, you can do this:
<li class="is-empty" data-bind="visible: products().length < 1">
<p>Your summary is empty.</p>
</li>
For the rest, you should be able to do this (no MVC loops):
<!-- ko foreach: products -->
<li data-bind="attr: { 'data-product-id': id }">
<div class="product-summary-actions float-right">
<button class="btn btn-danger btn-mini remove-item">
<i class="icon-remove"></i>
</button>
</div>
<div class="product-summary-quantity">
<h6 data-bind="text: infoComposition"></h6>
</div>
<div class="product-summary-description">
<p data-bind="text: name"></p>
</div>
</li>
<!-- /ko -->
And populate the list on the client side, even if you have items saved to the session. In your view, serialize the existing data to a JSON object and save it to a javascript variable on the page which can be read on document ready and pushed into the products observable.
var existingItems = #Html.Raw(Json.Encode((List<MyApp.Models.Data.getSpecificProductToShoppingList_Result>)Session["ProductsSummary"]));
$(document).ready(function() {
// push existingItems into products observable.
});
Note my syntax may not be quite right on the JSON encoding.