How does one place two buttons in one table cell with fluent bootstrap? - fluentbootstrap

I'm experimenting with Fluent Bootstrap but am finding the API documentation sparse. In the last cell of each table row I want to place two buttons (i.e. edit, delete). The problem is that the #row.TableData component builder is being passed two MVC HtmlStrings and is expecting a string? maybe
#using (var table = #Html.Bootstrap().Table().SetId("tblRoles").SetStyle(TableStyle.Bordered | TableStyle.Striped).SetResponsive().Begin())
{
#table.TableHeaderRow(
#Html.DisplayNameFor(model => model.Id),
#Html.DisplayNameFor(model => model.RoleTag),
#Html.DisplayNameFor(model => model.Status),
#Html.DisplayNameFor(model => model.Name),
""
)
foreach (var item in Model)
{
using (var row = #table.TableDataRow().Begin())
{
#row.TableData(#Html.DisplayFor(modelItem => item.Id))
#row.TableData(#Html.DisplayFor(modelItem => item.RoleTag))
#row.TableData(#Html.DisplayFor(modelItem => item.Status))
#row.TableData(#Html.DisplayFor(modelItem => item.Name))
#row.TableData(
#Html.ButtonWithIcon(null, "Edit", "RolesAdmin", new { id = item.Id }, new { #class = "btn btn-primary btn-xs", title = "Edit" }, "icomoon-pencil-5")
#Html.ButtonWithIcon(null, "Delete", "RolesAdmin", new { id = item.Id }, new { #class = "btn btn-danger btn-xs", title = "Delete" }, "icomoon-remove-2")
)
}
}
}

Seems like most everything can use the begin method to create a wrapper around inner elements such as:
#row.TableData().Begin()
{
#Html.ButtonWithIcon(null, "Edit", "RolesAdmin", new { id = item.Id }, new { #class = "btn btn-primary btn-xs", title = "Edit" }, "icomoon-pencil-5")
#Html.ButtonWithIcon(null, "Delete", "RolesAdmin", new { id = item.Id }, new { #class = "btn btn-danger btn-xs", title = "Delete" }, "icomoon-remove-2")
}
This works and produces the desired markup.

Related

Asp.net Core EF 3DropDown in series on Edit form, Save will delete fields in navigation properties tabels

I have 4 entities :
Vehicle, VehicleBrand, VehicleModel, VehicleVersion
in one-to-many relationship, code-first generated by ef.
Database look like that:
Edit form use jQuery, first dropdown is feeded by a ViewBag, and the other 2 by Json.
The Edit Form is that:
And when I save the DropDowns retrn ONLY id ! dooh !
But my Bind expect entity
As you can see vbName came back null and after SaveChanges.. in all entities have name field null
Here is the Controller code for Edit:
[HttpGet]
public async Task<IActionResult> YourEditNewCar(int? id)
{
if (id == null)
{
return NotFound();
}
var brands = await _context.VehicleBrands.OrderBy(b => b.vbName).Select(x => new { Id = x.id, Value = x.vbName }).ToListAsync();
var models = await _context.VehicleModels.OrderBy(m => m.vmName).ToListAsync();
var versions= await _context.VehicleVersions.OrderBy(v =>v.vvName).ToListAsync();
var model = new Vehicle();
ViewBag.BrandList = new SelectList(brands, "Id", "Value");
model = await _context.Vehicles.SingleOrDefaultAsync(m => m.id == id);
if (model == null)
{
return NotFound();
}
return View("~/Views/Manage/YourEditNewCar.cshtml", model);
}
public JsonResult getVehicleModelById(int id)
{
List<VehicleModel> vehicleModelList = new List<VehicleModel>();
vehicleModelList = _context.VehicleModels.Where(m => m.VehicleBrand.id == id).OrderBy(m => m.vmName).ToList(); //.Select(y => new { Id = y.id, Value = y.vmName })
vehicleModelList.Insert(0, new VehicleModel { id = 0, vmName = "Car Model" });
return Json(vehicleModelList);
}
public JsonResult getVehicleVersionById(int id)
{
List<VehicleVersion> vehicleVersionList = new List<VehicleVersion>();
vehicleVersionList = _context.VehicleVersions.Where(m => m.VehicleModel.id == id).OrderBy(m => m.vvName).ToList(); //.Select(y => new { Id = y.id, Value = y.vmName })
vehicleVersionList.Insert(0, new VehicleVersion { id = 0, vvName = "Car Version" });
return Json(vehicleVersionList);
}
and the post:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> YourEditNewCar(int id, [Bind("id,DoorsNr,isAvailable,isDamaged,isDeleted,FabricationDate,FuelTankCapacity,TrunckCapacity,OnBoardKm,SeatNr," +
"LicencePlate, VehicleBrand, VehicleModel, VehicleVersion")] Vehicle vehicle)
{
var user = await _userManager.GetUserAsync(User);
if (ModelState.IsValid)
{
try
{
_context.Update(vehicle);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!VehicleExists(vehicle.id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction("YourCar", "Manage");
}
return View(vehicle);
}
in the Edit form dropdowns look like this:
<hr>
<div class="col-md-12 text-center"><h4> Please select :</h4></div>
<div class="row row-list">
<div class="form-group col-xs-4">
<label asp-for="VehicleBrand" class="control-label hidden" value=""></label>
#Html.DropDownListFor(model => model.VehicleBrand.id, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", #class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleModel" class="control-label hidden" value=""></label>
#Html.DropDownListFor(model => model.VehicleModel.id, new SelectList(string.Empty), "Car Model", new { style = "width: 120px;", #class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleVersion" class="control-label hidden" value=""></label>
#Html.DropDownListFor(model => model.VehicleVersion.id, new SelectList(string.Empty), "Car Version", new { style = "width: 110px;", #class = "form-control" })
</div>
</div>
and the scrip from edit form, to feed dropdowns, is like that:
<script>
$(function () {
$("#VehicleBrand_id").change(function () {
//alert("Vehicle Brand dd changed !");
var url = '#Url.Content("~/Manage/getVehicleModelById")';
var ddlsource = "#VehicleBrand_id";
$.getJSON(url, { id: $(ddlsource).val() }, function (data) {
var items = '';
$("#VehicleModel_id").empty();
$.each(data, function (i, row) {
items += "<option value='" + row.id + "'>" + row.vmName + "</option>";
});
$("#VehicleModel_id").html(items);
})
});
});
</script>
All dropdowns works perfect, the return is just id.
And when I SaveChanges, even if I want to save Only in Vehicle table, it update in other entities too, by navigation properties.
_context.Update(vehicle);
await _context.SaveChangesAsync();
I tried this to not Update VehicleBrands, but doesn't have effect :
and this need a new object:
I feel that I'm missing something simple, or is a wrong approach.
The problem Was in Model! I used Just: public VehicleBrand VehicleBrand { get; set; }
Without declaring field as ForeignKey
I added in model:
[ForeignKey("VehicleVersionid")]
public int VehicleVersionid { get; set; }
Now I added (with Bold) in Model:
[ForeignKey("VehicleBrandid")]
public int VehicleBrandid { get; set; }
public VehicleBrand VehicleBrand { get; set; }
[ForeignKey("VehicleModelid")]
public int VehicleModelid { get; set; }
public VehicleModel VehicleModel { get; set; }
[ForeignKey("VehicleVersionid")]
public int VehicleVersionid { get; set; }
public VehicleVersion VehicleVersion { get; set; }
And edited in :
[HttpPost]
[ValidateAntiForgeryToken]
public async Task YourEditNewCar(int id,[Bind("id,DoorsNr,isAvailable,isDamaged,isDeleted,FabricationDate,FuelTankCapacity,TrunckCapacity,OnBoardKm,SeatNr," +
"LicencePlate, VehicleBrandid, VehicleModelid, VehicleVersionid")] Vehicle vehicle)
Thanks for your patience!:)
Works like a charm ! :)
You should be using
#Html.DropDownListFor(model => model.VehicleBrandid, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", #class = "form-control" })
not
#Html.DropDownListFor(model => model.VehicleBrand.id, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", #class = "form-control" })
Bind your dropdown list to the id field in vehicle entity, not to the id field in the related entity.
Or if you wanted to start using taghelpers in asp.net core you could use this reference: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms#the-select-tag-helper
The issue with the code is, mvc modelstate validation processing with respected to the model used in your posted view. So in this your model is vehicles, so with respect vehicle we need to give values for model. vehicleBrand, VehicleModel, VehicleVersion are different model and the value in that field not have any dependencies on Vehicles model at posting time. so in view you need to use like this
<div class="row row-list">
<div class="form-group col-xs-4">
<label asp-for="VehicleBrand" class="control-label hidden" value=""></label>
#Html.DropDownListFor(model => model.VehicleBrandid, (SelectList)ViewBag.BrandList, "Car Brand", new { style = "width: 140px;", #class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleModel" class="control-label hidden" value=""></label>
#Html.DropDownListFor(model => model.VehicleModelid, new SelectList(string.Empty), "Car Model", new { style = "width: 120px;", #class = "form-control" })
</div>
<div class="form-group col-xs-4">
<label asp-for="VehicleVersion" class="control-label hidden" value=""></label>
#Html.DropDownListFor(model => model.VehicleVersionid, new SelectList(string.Empty), "Car Version", new { style = "width: 110px;", #class = "form-control" })
</div>
</div>
and once one model used in view it is will we changed the whole property as entity then it be difficult to manage and check entitystate.unchanged property

Dynamic partial view list not being picked up when saving

I have a partial view that gets rendered in my main view using this code
<div>
<h3>Budget Detail</h3>
<div><input type="button" id="addbudgetdetail" value="Add row" /></div>
<div id="new-budgetdetail">
#if (Model.budget != null)
{
foreach (var budgetdetail in Model.budget.budgetdetails)
{
#Html.Partial("budgetdetail", Model)
}
}
else
{
#Html.Partial("budgetdetail", Model)
}
</div>
</div>
There is a java script to dynamically add more partial views when clicking a button
$(function () {
$('#addbudgetdetail').on('click', function () {
jQuery.get('#Url.Action("budgetdetail")').done(function (html) {
$('#new-budgetdetail').append(html);
$('form').data('validator', null);
$.validator.unobtrusive.parse($('form'));
});
});
});
This is My partial view:
#model BudgetPortalMVC4.Models.NewBudgetModel
#{
Layout = null;
}
<script src="../../Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
#using (Html.BeginCollectionItem(""))
{
#Html.ValidationSummary(true)
<div class="item">
<table>
<tr>
<td>
#Html.LabelFor(m => m.SelectedCategory)
#Html.DropDownListFor(m => m.SelectedCategory, Model.CategoriesList, "Please select", new { #class = "SelectedCategory" })
#Html.ValidationMessageFor(m => m.SelectedCategory)
</td>
<td>
#Html.LabelFor(m => m.SelectedSubCategory)
#Html.DropDownListFor(m => m.SelectedSubCategory, Model.SubCategoriesList, "Please select", new { #class = "SelectedSubCategory" })
#Html.ValidationMessageFor(m => m.SelectedSubCategory)
</td>
<td>
#Html.LabelFor(model => model.budgetdetail.Amount)
#Html.EditorFor(model => model.budgetdetail.Amount)
#Html.ValidationMessageFor(model => model.budgetdetail.Amount)
</td>
<td><a href="#" id="deleteRow" class="deleteRow">Delete</a</td>
</tr>
</table>
</div>
}
My problem is when I click submit I don't see any list for my partial views.
I can only see the data that is coming directly from my main view.
Am I missing an IEnumerable property somewhere? Should I try to use editor templates instead?
I have solved this problem. I had to rework the models and instead of using a big model grouping the budget and budget detail, i am using 2 models one for budget and one for budgetdetail.
I also rewrote the dropdown lists to comply to the new model:
#Html.LabelFor(m => m.category)
#Html.DropDownListFor(m => m.idCategory, new SelectList(ViewBag.CategoriesList, "idCategory", "CategoryName"), "Please select", new { #class = "SelectedCategory" })
#Html.ValidationMessageFor(m => m.idCategory)
#Html.LabelFor(m => m.subcategory)
#Html.DropDownListFor(m => m.idSubcategory, new SelectList(ViewBag.SubCategoriesList, "Value", "Text"), "Please select", new { #class = "SelectedSubCategory" })
#Html.ValidationMessageFor(m => m.idSubcategory)
Instead of using a partial view I created an editor template. Following Stephen's advice that BeginCollection can't be use in editor templates I used an html helper to create unique items in my collection.
This is the code for the helper:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace BudgetPortalMVC4.Extensions
{
public static class HtmlHelperExtensions
{
public static MvcHtmlString EditorForMany<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TValue>>> expression, string htmlFieldName = null) where TModel : class
{
var items = expression.Compile()(html.ViewData.Model);
var sb = new StringBuilder();
if (String.IsNullOrEmpty(htmlFieldName))
{
var prefix = html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
htmlFieldName = (prefix.Length > 0 ? (prefix + ".") : String.Empty) + ExpressionHelper.GetExpressionText(expression);
}
foreach (var item in items)
{
var dummy = new { Item = item };
var guid = Guid.NewGuid().ToString();
var memberExp = Expression.MakeMemberAccess(Expression.Constant(dummy), dummy.GetType().GetProperty("Item"));
var singleItemExp = Expression.Lambda<Func<TModel, TValue>>(memberExp, expression.Parameters);
sb.Append(String.Format(#"<input type=""hidden"" name=""{0}.Index"" value=""{1}"" />", htmlFieldName, guid));
sb.Append(html.EditorFor(singleItemExp, null, String.Format("{0}[{1}]", htmlFieldName, guid)));
}
return new MvcHtmlString(sb.ToString());
}
}
}
Now I call the template from the main using an intermediate IEnumerable view.
This is the call from the main view:
#Html.EditorForMany(x => x.budgetdetails)
And this is the intermediate IEnumerable view:
#model IEnumerable<BudgetPortalMVC4.Models.budgetdetail>
#{
Layout = null;
}
#Html.EditorForMany(x => x, "budgetdetails")
Hope this is helpful.

How to pass the Checkbox Checked or Not to Controller from View in MVC4

I am using MVC4 with razor view and I want to pass the Checkboxfor's Checked or Not value to Controller's create method from Create View but in the post method I am getting null value in m_category.IsActive so can anyone help me to solve my problem ,My Create view as per given below
#model Test.Models.M_Category
....
#using (Html.BeginForm("Create", "Category"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
....
<div class="form-group">
#Html.LabelFor(model => model.CategoryName, "Category Name")
#Html.TextBoxFor(model => model.CategoryName, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CategoryName)
</div>
<div class="form-group">
#Html.LabelFor(model => model.IsActive, "Is Active")
#Html.CheckBoxFor(model => model.IsActive.Value, new { #class = "checkbox" })
#Html.ValidationMessageFor(model => model.IsActive)
</div>
....
}
and my create controller method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(M_Category m_category)
{
if (ModelState.IsValid)
{
M_Category obj = new M_Category();
obj = db.M_Category.Where(x => x.CategoryName.ToLower() == m_category.CategoryName && x.CategoryID!=m_category.CategoryID && x.IsDeleted == false).FirstOrDefault();
if (obj == null)
{
obj = new M_Category();
obj = db.M_Category.Find(m_category.CategoryID);
obj.IsActive = m_category.IsActive;//here I am getting null value
obj.CategoryName = m_category.CategoryName;
db.Entry(obj).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
TempData["exists"] = "record already exists.";
return RedirectToAction("Index");
}
Thanks in advance..

How to add two button in grid.mvc control in mvc

I want to add two button control in one column. currently i can able to add Download button on one column . but i want to add delete button beside to download button in same columns.
please suggest on the same.
I have given code..
#using (Html.BeginForm("DownloadFile", "Download", FormMethod.Post))
{
#Html.Grid(Model).Columns(columns =>
{
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(0)
.RenderValueAs(o => #<input id="id" name="IsChecked" value= #o.id , type="checkbox"/>);
columns.Add(data => data.FileName).Titled("File Name").SetWidth(50);
columns.Add(data => data.DisplayedDate).Titled("Uploaded Date").SetWidth(40);
columns.Add(data => data.User_Name).Titled("User Name").SetWidth(50);
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(80)
.RenderValueAs(data => #<button type="submit" value ="">Download</button>);
}).WithPaging(10).Sortable(true).Filterable(true)}
One of the overload for RenderValueAs accepts IHtmlString.
So you can do:
.RenderValueAs(data => new HtmlString
(
"<button type='submit' value=''>Download</button>
<button type='button' value=''>Upload</button>"
)
);
Or you can do:
.RenderValueAs(data => "<button type='submit' value=''>Download</button>
<button type='button' value=''>Upload</button>"
);
If you need more control, there is a Custom Layout rendering feature that you can use.
columns.Add(c => c.PrecioVenta).Titled("Precio de Venta").Filterable(true);
columns.Add(c => c.Cantidad).Titled("Cantidad").Filterable(true);
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(30)
.RenderValueAs(o => Html.ActionLink("Editar", "Edit", new { id = o.IdProducto }, new { #class = "btn btn-primary" }));
columns.Add()
.Encoded(false)
.Sanitized(false)
.SetWidth(30)
.RenderValueAs(o => Html.ActionLink("Detalles", "Details", new { id = o.IdProducto }, new { #class = "btn btn-info" }));

EditorFor within an EditorFor and Inheritance

I've got a View rendering an EditorFor of an AgreementSearch object, which in turn has an EditorFor of a BaseEmployeeSearch object since AgreementSearch inherits from BaseEmployeeSearch. The issue is that the EditorFor the BaseEmployeeSearch object has returns with nothing in it.
When used separately the BaseEmployeeSearch objects EditorTemplate works just fine, and if the issue were because of a misname or something I would expect the object's .ToString editor to come up by default.
Could someone shed some light on this?
AgreementSearch Edit Template:
#model TimecardRepository.Models.AgreementsModels.BusinessObject.AgreementSearch
#Html.EditorForModel("_BaseEmployeeSearch")
<h4>HEY THERE!</h4>
<span class="margin_left_2em">
#Html.LabelFor(x => x.AgreementStatus, "Filter by agreement Type: ")
#Html.DropDownListFor(x => x.AgreementStatus, new SelectList(new[]
{
new { desc = "All agreement types", value = "0" },
new { desc = "Disagreements Only", value = "1" },
new { desc = "Agreements Only", value = "2" },
new { desc = "Awaiting Agreement", value = "3" }
}, "value", "desc", (Model != null) ? Model.AgreementStatus : 0))
</span>
<span class="margin_left_2em">
#Html.LabelFor(x => x.AgreementStatus, "Filter by last comment: ")
#Html.DropDownListFor(x => x.AgreementStatus, new SelectList(new[]
{
new { desc = "All comment types", value = "0" },
new { desc = "No comments", value = "1" },
new { desc = "Last comment from Payroll", value = "2" },
new { desc = "Last comment from Field", value = "3" }
}, "value", "desc", (Model != null) ? Model.CommentStatus : 0))
</span>
BaseEmployeeSearch Edit Template
#model TimecardRepository.Models.Shared.BaseEmployeeSearch
<span>
#Html.LabelFor(model => Model.FirstName, "First: ")
#Html.TextBoxFor(model => Model.FirstName, new { style = "width: 7em;", maxlength = "12" })
</span>
<span class="margin_left_2em">
#Html.LabelFor(model => Model.LastName, "Last: ")
#Html.TextBoxFor(model => Model.LastName, new { style = "width: 7em;", maxlength = "12" })
</span>
<span class="margin_left_2em">
#Html.LabelFor(model => Model.MemberID, "SMID: ")
#Html.TextBoxFor(model => Model.MemberID, new { style = "width: 6em;", maxlength = "7" })
</span>
<span class="margin_left_2em">
#Html.LabelFor(model => Model.Entity, "Entity: ")
#Html.TextBoxFor(model => Model.Entity, new { style = "width: 5em;", maxlength = "6" })
</span>
<span class="margin_left_2em">
#Html.LabelFor(model => Model.PayPeriod.Offset, "Pay Period: ")
#Html.DropDownListFor(model => Model.PayPeriod.Offset, new SelectList(new[] { new { desc = "Current", value = "0" }, new { desc = "Next", value = "1" }, new { desc = "Previous", value = "-1" } }, "value", "desc"))
#Html.HiddenFor(model => Model.PayPeriod.StartDate)
#Html.HiddenFor(model => Model.PayPeriod.EndDate)
</span>