I have an html table that holds categories of things. Each row consists of a category id and name that are looped in from the model. There are also two buttons in each row. One that I want to use to set the state of the row to enabled and the other to set it to disabled:
http://codepen.io/cavanflynn/pen/waPXww - This codepen shows how I'm working the buttons on the front end
<table id="categoryList" class="table">
<thead>
<tr>
<th>Category ID</th>
<th>Category Name</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Categories)
{
<tr>
<td>#item.id</td>
<td>#item.name</td>
<td>
<button class="btn btn-success categoryEnabled">Enabled</button>
<button class="btn btn-danger categoryDisabled" style="display: none;">Disabled</button>
</td>
</tr>
}
</tbody>
</table>
When I say set to enabled or disabled I mean change the bit value for that row in an SQL table column called state. So, I basically just need the buttons to toggle that bit value for the row in which it is clicked. I have been struggling to figure out the method to do this.
Example controller code to help out:
public ActionResult SaveCategory(int categoryId, String categoryName)
{
var connection = new CategoryDBEntities();
if (categoryId > 0)
{
var rsc = connection.QualityCategories.Find(categoryId);
rsc.name = categoryName;
}
else
{
QualityCategory rsc = new QualityCategory();
rsc.name = categoryName;
connection.QualityCategories.Add(rsc);
}
connection.SaveChanges();
return Redirect(System.Web.HttpContext.Current.Request.UrlReferrer.AbsolutePath);
}
(This code is used to save category changes)
Any help would be appreciated. Thanks!
Assuming your Category object looks something like:
public enum StatesTypes
{
Disabled = 0,
Enabled = 1
}
public class Category
{
public int Id { get; set; }
public StatesTypes State { get; set; }
public String Name { get; set; }
}
Perhaps then you could have a SaveCategory method within your Controller which returns back a Json object.
public JsonResult SaveCategory(StatesTypes state, int categoryId)
{
CategoryJsonViewModel ret = new CategoryJsonViewModel();
ret.Response = //Use EF here - perhaps call a service object to save the category?
if(ret.Response == BaseJsonResponseTypes.Success)
{
if(state == StatesTypes.Disabled)
{
ret.Message = "Category successfully disabled";
}
else
{
ret.Message = "Category successfully enabled";
}
}
else
{
ret.Message = "Critical error :-(";
}
return Json(ret);
}
Dependency classes (up to you how you do this):
public enum BaseJsonResponseTypes
{
NotSet = 0,
Error = 1,
Success = 2
}
public class BaseJsonViewModel
{
public BaseJsonResponseTypes Response { get; set; }
public String Message { get; set; }
}
public class CategoryJsonViewModel : BaseJsonViewModel
{
//Maybe you could include some implemention here.
}
Your jQuery would look something like:
$(".disable").on("click", function(){
$(this).hide();
$(this).next().show();
var id = $(this).data('val');
SaveCategory(0, id);
});
$(".enable").on("click", function(){
$(this).hide();
$(this).prev().show();
var id = $(this).data('val');
SaveCategory(1, id);
});
function SaveCategory(state, id) {
var obj = {
state: state,
categoryId: id
};
$.ajax({
type: "POST",
url: "/category/savecategory",
contentType: "application/json; charset=utf-8",
data : JSON.stringify(obj),
dataType: "json",
success: function(data) {
//Do something cool with the data object?
alert(data.Message);
}
});
}
data-val attribute has been added, as shown (this passes through the category id):
<button class="disable" data-val="#item.id">Disable</button>
<button class="enable" style="display:none;" data-val="#item.id">Enable</button>
You need to give your buttons some way to pass the specific row identifier to the back-end, so that it knows which row to effect.
<button class="disable" id="Row1Disable">Disable</button>
Then you will need to hook up your jquery post method to your controller action, something something like this:
$(".disable").on("click", function(){
$(this).hide();
$(this).next().show();
$.post("#Url.Action("DisableRow", "MyController")", { "Id": $(this).attr('id') }, function (response) {
if (response.success) {
// Handle successful disabled post.
alert('Row Disabled!');
} else {
// Handle error.
alert('Error disabling row!');
}
});
});
$(".enable").on("click", function(){
$(this).hide();
$(this).prev().show();
$.post("#Url.Action("EnableRow", "MyController")", { "Id": $(this).attr('id') }, function (response) {
if (response.success) {
// Handle successful disabled post.
alert('Row Enabled!');
} else {
// Handle error.
alert('Error enabling row!');
}
});
});
Once the posts are hooked up to proper controller actions, you should be good to go. Here's the codePen based on your original one: http://codepen.io/anon/pen/xGPzZW?editors=101
Edit exemplifying ID uniqueness in loop:
using for loop:
for(int i = 0; i < rows.Count(); i++)
{
string id = "Row" + i.ToString() + "Enable";
// do the rest...
}
using while / foreach loop:
int i = 0;
foreach (var row in Model.Rows)
{
string id = "Row" + i.ToString() + "Enable";
i +=1;
// do the rest...
}
Related
I have two related models.
public partial class bs_delivery_type
{
public decimal delivery_id { get; set; }
public decimal delivery_city_id { get; set; }
public string delivery_address { get; set; }
public virtual bs_cities bs_cities { get; set; }
}
and the second one:
public partial class bs_cities
{
public bs_cities()
{
this.bs_delivery_type = new HashSet<bs_delivery_type>();
}
public decimal cities_id { get; set; }
public string cities_name { get; set; }
public virtual ICollection<bs_delivery_type> bs_delivery_type { get; set; }
}
and I have such ViewBag's for dropdownlist's:
ViewBag.city = new SelectList(_db.bs_cities, "cities_id", "cities_id");
ViewBag.delivery_adress = new SelectList(_db.bs_cities, "delivery_id", "delivery_address");
When I choose city in first dropdownlist, in the second one there has to be appeared binded list with delivery_adress, where delivery_city_id = cities_id(from first dropdownlist).
How to do that?
Edit:
I tryed method from #Izzy's comment, so here is my actual view:
#model Bike_Store.Models.DeliveryModel
#{
ViewBag.Title = "Checkout";
}
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/jquery-3.1.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
<script type="text/javascript">
function GetDelivery(_stateId) {
var procemessage = "<option value='0'> Please wait...</option>";
$("#ddldelivery").html(procemessage).show();
var url = "/Shop/GetDeliveryByCityId/";
$.ajax({
url: url,
data: { cities_id: _stateId },
cache: false,
type: "POST",
success: function (data) {
var markup = "<option value='0'>Select adress</option>";
for (var x = 0; x < data.length; x++) {
markup += "<option value=" + data[x].Value + ">" + data[x].Text + "</option>";
}
$("#ddldelivery").html(markup).show();
},
error: function (reponse) {
alert("error : " + reponse);
}
});
}
</script>
<h2>Checkout</h2>
#using (Html.BeginForm())
{
#Html.DropDownListFor(m=>m.CitiesModel, new SelectList(Model.CitiesModel, "cities_id", "cities_name"), new {#id = "ddldelivery", #style="width:200px", #onchange="javascript:GetDelivery(this.value);"})
<br />
<br />
<select id="ddldelivery" name="ddldelivery" style="width:200px">
</select>
<br /><br />
}
My controller now looks like this:
public List<bs_cities> GetAllCities()
{
List<bs_cities> cities = new List<bs_cities>();
foreach (var city in _db.bs_cities)
{
cities.Add(city);
}
return cities;
}
public List<bs_delivery_type> GetAllDeliveries()
{
List<bs_delivery_type> deliveries = new List<bs_delivery_type>();
foreach (var delivery in _db.bs_delivery_type)
{
deliveries.Add(delivery);
}
return deliveries;
}
[HttpPost]
public ActionResult GetDeliveryByCityId(decimal cities_id)
{
List<bs_delivery_type> delivery = new List<bs_delivery_type>();
delivery = GetAllDeliveries().Where(m => m.delivery_city_id == cities_id).ToList();
SelectList objDelivery = new SelectList(delivery, "delivery_id", "delivery_address", 0);
return Json(objDelivery);
}
public ViewResult Checkout()
{
DeliveryModel deliveryModel = new DeliveryModel();
deliveryModel.CitiesModel = new List<bs_cities>();
deliveryModel.CitiesModel = GetAllCities();
return View(deliveryModel);
}
The problem now is that i have 2 ddls, but works only first one.
In scrshot you can see I have a list of cities, when I choose a city, in this same ddl appears a list of delivery adresses, and when I choose adress - its desappears. What a magic? Help me please with Ajax.
List of cities
I guesse i fixed it, the problem was in:
#Html.DropDownListFor(m=>m.CitiesModel, new SelectList(Model.CitiesModel, "cities_id", "cities_name"), new {#id = "ddldelivery", #style="width:200px", #onchange="javascript:GetDelivery(this.value);"})
I changes #id = "ddldelivery" to #id = "ddlcity" and it works now
The following guide will show you:
Create a partial view
Takes cityid as input and outputs the delivery address list
Load partial view into your select
Note: Partial view solution may be overkill in this situation, but for similar problems it is actually quite usefull.
PartialView .cshtml
Filename: _deliveryTypePartial.cshtml
#model List<bs_delivery_type>
#foreach(var item in Model)
{
<option value="#item.delivery_id">
#item.delivery_address
</option>
}
Controller Code for Partial View:
public IActionResult _deliveryTypePartial(decimal city_id)
{
List<bs_delivery_type> model = context.bs_delivery_types.Where(row => row.delivery_city_id == delivery_city_id).ToList();
return PartialView(model);
}
And then Finally, for your AJAX
I notice that your two dropdownlists have identical ID's witch will cloud your javascript code and is considered bad practice, so for the purposes of this guide I will call the first dropdownlist:
ddlcity
Now, inside your onchange function for ddlcity:
$('#ddldelivery').load("/ControllerName/_deliveryTypePartial?city_id=" _stateId);
This should load the partial view into your second dropdown list.
PS: As I completed this question you had already used the direct ajax method, I agree that both methods are equally suitable in this case. You can perhaps use the method outlined here if the actual objects you need to populate are a lot more complex.
In a MVC partial view file, I build one Html.TextBox and two submit buttons. These two buttons will increase/decrease the Html.TextBox value once clicked. The Html.TextBox displayed value will change accordingly.However, once I need to update the #refTable div based on the new value after click. The page or section never updated. Codes are below, where some comments are added for explanation purpose. Thanks for your help.
//******* cshtml file **********//
<body>
</body>
<input type="submit" value="PrevY" name="chgYr2" id="pY" />
#{
var tempItem3 = Model.First(); // just give the first entry from a database, works.
if (ViewData["curSel"] == null)
{
#Html.TextBox("yearSelect3", Convert.ToDateTime(tempItem3.Holiday_date).Year.ToString());
ViewBag.selYear = Convert.ToDateTime(tempItem3.Holiday_date).Year; // just initial value, works
ViewData["curSel"] = Convert.ToDateTime(tempItem3.Holiday_date).Year;
}
else
{
#Html.TextBox("yearSelect3", ViewData["curSel"].ToString());
}
}
<input type="submit" value="NextY" name="chgYr2" id="nY" />
<script type="text/javascript">
$(document).ready(function () {
$(document).on("click", "#nY", function () {
var val = $('#yearSelect3').val();
$('#yearSelect3').val((val * 1) + 1);
var dataToSend = {
id: ((val * 1) + 1)
}
// add some jquery or ajax codes to update the #refTable div
// also ViewBag.selYear need to be updated as ((val * 1) + 1)
// like: ViewBag.selYear = ((val * 1) + 1);
// any similar temp variable is fine
});
});
$(document).on("click", "#pY", function () {
var val = $('#yearSelect3').val();
$('#yearSelect3').val((val * 1) - 1);
var dataToSend = {
id: ((val * 1) - 1)
}
});
});
</script>
<span style="float: right">Set Holiday Calender for 2013</span>
<span id="btnAddHoliday">#Html.ActionLink("Add Holiday", "Create", null, new { id = "addHilBtn" })</span>
<div id="refTable">
<table class="tblHoliday" style="width: 100%;">
<th>
Holiday
</th>
<th>
Dates
</th>
<th>Modify</th>
<th>Delete</th>
</tr>
#foreach (var item in Model)
{
if ( Convert.ToDateTime(item.Holiday_date).Year == ViewBag.selYear)
// if the ViewBag.selYear is hard code, this selection "works"
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Holiday_Name)
</td>
<td>
#item.Holiday_date.Value.ToString("MM/dd/yyyy")
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { })
</td>
<td>
#Html.ActionLink("Delete", "Delete", new { })
</td>
</tr>
}
}
</table>
</div>
You'll need AJAX if you want to update a part of your page without reloading the entire page.
main cshtml view
<div id="refTable">
<!-- partial view content will be inserted here -->
</div>
#Html.TextBox("yearSelect3", Convert.ToDateTime(tempItem3.Holiday_date).Year.ToString());
<button id="pY">PrevY</button>
<script>
$(document).ready(function() {
$("#pY").on("click", function() {
var val = $('#yearSelect3').val();
$.ajax({
url: "/Holiday/Calendar",
type: "GET",
data: { year: ((val * 1) + 1) }
})
.done(function(partialViewResult) {
$("#refTable").html(partialViewResult);
});
});
});
</script>
You'll need to add the fields I have omitted. I've used a <button> instead of submit buttons because you don't have a form (I don't see one in your markup) and you just need them to trigger javascript on the client side.
The HolidayPartialView gets rendered into html and the jquery done callback inserts that html fragment into the refTable div.
HolidayController Update action
[HttpGet]
public ActionResult Calendar(int year)
{
var dates = new List<DateTime>() { /* values based on year */ };
HolidayViewModel model = new HolidayViewModel {
Dates = dates
};
return PartialView("HolidayPartialView", model);
}
This controller action takes the year parameter and returns a list of dates using a strongly-typed view model instead of the ViewBag.
view model
public class HolidayViewModel
{
IEnumerable<DateTime> Dates { get; set; }
}
HolidayPartialView.csthml
#model Your.Namespace.HolidayViewModel;
<table class="tblHoliday">
#foreach(var date in Model.Dates)
{
<tr><td>#date.ToString("MM/dd/yyyy")</td></tr>
}
</table>
This is the stuff that gets inserted into your div.
The main concept of partial view is returning the HTML code rather than going to the partial view it self.
[HttpGet]
public ActionResult Calendar(int year)
{
var dates = new List<DateTime>() { /* values based on year */ };
HolidayViewModel model = new HolidayViewModel {
Dates = dates
};
return PartialView("HolidayPartialView", model);
}
this action return the HTML code of the partial view ("HolidayPartialView").
To refresh partial view replace the existing item with the new filtered item using the jQuery below.
$.ajax({
url: "/Holiday/Calendar",
type: "GET",
data: { year: ((val * 1) + 1) }
})
.done(function(partialViewResult) {
$("#refTable").html(partialViewResult);
});
You can also use Url.Action for the path instead like so:
$.ajax({
url: "#Url.Action("Holiday", "Calendar", new { area = "", year= (val * 1) + 1 })",
type: "GET",
success: function (partialViewResult) {
$("#refTable").html(partialViewResult);
}
});
I want design page like this
up to now I have created like this . I want to know bind check-box front of each row and send those checked/non-checked values with IDs using json and jquery
this last code snippet of that page
<div style="width:50%; float:left;text-align:left"><button id="resetborchure" type="button" class="btn btn-warning submit">Reset Brochure</button> </div>
<div style="width:50%; float:left;text-align:right"><button id="createborchure" type="button" class="btn btn-danger submit">Create Brochure</button> </div>
<script type="text/javascript">
</script>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/jqueryui")
<script type="text/javascript">
var url = '#Url.Action("FetchProductProperties")';
var editUrl = '#Url.Action("Edit")';
var type = $('#Type');
var category = $('#Category');
var country = $('#Country');
var product = $('#Product');
var template = $('#template');
var table = $('#table');
$('#search').click(function () {
table.empty();
$.getJSON(url, { type: type.val(), category: category.val(), country: country.val(), product: product.val() }, function (data) {
$.each(data, function (index, item) {
var clone = template.clone();
var cells = clone.find('td');
cells.eq(0).text(item.ID);
cells.eq(1).text(item.Name);
table.append(clone.find('tr'));
});
});
});
$('#resetborchure').click(function () {
table.empty();
});
</script>
}
Also I want , once I checked and click create brochure button I want send those checked/non-checked values with IDs using json
I have try to put to populate a checkbox with each listed result '<td><input type="checkbox" /></td>' inside cells.eq(1).text(item.Name);
as cells.eq(1).text('<td><input type="checkbox" /></td>'+item.Name); but this is not working
Once I click "Select Information" button Its list down data from AB_Product_Property table , IF I want to populate check-box with each search result row Do I need maintain boolean field in that table also ?? I want to do this without maintain column for that boolean field in AB_Product_Property table
Create a view model(s) to represent what you want to display/edit.
public class OptionsVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class SearchVM
{
public int Asset { get; set; }
public SelectList AssetList { get; set; }
public int Category{ get; set; }
public SelectList CategoryList { get; set; }
.... // other properties and SelectLists for the dropdownlists
public List<OptionsVM> Options { get; set; }
}
and in the GET method, populate the Options with the ID and Name properties
Then in the view
#model SearchVM
....
<form>
#Html.DropDownListFor(m => m.Asset, Model.AssetList)
....
#for(int i = 0; i < Model.Options.Count; i++)
{
#Html.HiddenFor(m => m.Options[i].ID)
#Html.CheckBoxFor(m => m.Options[i].IsSelected)
#Html.LabelFor(m => m.Options[i].IsSelected, Model.Options[i].Name)
}
<button type="button" id="createbrochure">Create Brochure</button>
and in the script
$('#createbrochure').click(function () {
$.getJSON(url, $('form').serialize(), function (data) {
....
});
})
and in the controller method
public ActionResult CreateBrochure(SearchVM model)
{
// To get the ID's of all selected options
IEnumerable<int> selectedOptions = model.Options.Where(o => o.IsSelected).Select(o => o.ID);
....
}
You can create new column for check box instead of appending check box to name column.
Than you can set class to that check box and get the checked or unchecked check box value using jquery.
I have a list of Items that I want the user to sort using a Jquery sortable.
the structure of the items is like this:
public class SortableItems
{
public int Code { get; set; }
public byte? Priority { get; set; }
public string Name { get; set; }
public int IsActive { get; set; }
}
in my view I render the sortable inside a form in the following way:
#using (Html.BeginForm("TestAction", "TestController", FormMethod.Post, new { id = "submitTest" }))
{
<ul id="sortable" style="padding:0px;">
#for (int i = 0; i < Model.List.Count(); i++)
{
<li class="ui-state-default">
#Html.HiddenFor(x => Model.List[i].Code, new { #class = "id" })
#Html.HiddenFor(x => Model.List[i].Priority, new { #class = "order" })
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
#Model.List[i].Name
</li>
}
</ul>
<input type="submit" class="btn btn-primary" value="Update" />
}
Now the user can sort the N items in the list to their hearts desire. But I have not found a way to update the pidden value for Priority (order of the items that the user has sorted)
How can I persist the order of the items to my controller?
this is how I managed to solve the problem:
on the client side I did the following:
var neworder = new Array();
$("#sortable").disableSelection();
$("#sortable").sortable({
stop: function (event, ui) {
neworder = new Array();
$('#sortable li').each(function () {
//get the id
var id = $(this).attr("data-id");
neworder.push(id);
});
}
});
$(function () {
$('#submitTest').submit(function () {
if (neworder.length < 1) {
return false;
}
$.ajax({
url: "GuardarPrioridad", type: "POST", dataType: "json",
data: { orden: neworder.toString() },
success: function (result) {
$('#ShowResultHere').text(result);
$("#submitTest").hide();// .tex.html(result);
}
});
return false;
});
});
each time the user moves an element I update an array that conatins the IDs of the elements in the order that the user put them in.
I then submit this array via ajax and it is recieved by the controller.
and my controller looks like this:
public JsonResult SavePriority(string orden)
{
string[] data= orden.Split(',');
for (int i = 0; i < droguerias.Length; i++)
{
//save to DB
}
return Json("Saved!");
}
I my view I can add 'actions'. A action can be a email or sms. If i make a action i show a table in the view. So if I have 5 actions and I push on the submit button then i want the actions send to the Model.
My View:
<table id="action-detail-table" class="table table-striped table-bordered detail-table hide">
<thead id="headActions"></thead>
<tbody id="allActions"></tbody>
</table>
#Html.HiddenFor(m => m.Actions.Type, new { id = "action-types-type", name = "action-types-type" })
#Html.HiddenFor(m => m.Actions.Contact, new { id = "action-types-contact", name = "action-types-contact" })
Javascript in the view:
$('#addAlertModal form').submit(function (e) {
var actionType = new Array();
var contact = new Array();
$('#allActions tr').each(function () {
actionType.push(JSON.stringify($(this).find("td:eq(0)").text()));
contact.push(JSON.stringify($(this).find("td:eq(1)").text()));
});
$('#action-types-type').val(actionType);
$('#action-types-contact').val(contact);
});
function addAction() {
if ($.trim($('#allActions').find('td').text()).length == 0) {
$('#headActions').append("<tr><th>Actie</th><th>Naar</th></tr>");
}
if ($('#action-type').val() == "Email") {
$('#allActions').append($('#allActions').innerHTML + "<tr><td> Email </td><td>" + $('#action-email').val() + "</td></tr>");
}
else if ($('#action-type').val() == "SMS") {
$('#allActions').append($('#allActions').innerHTML + "<tr><td> SMS </td><td>" + $('#action-sms').val() + "</td></tr>");
}
}
And my Model:
public class AlertAction
{
public List<string> Type { get; set; }
public List<string> Contact { get; set; }
}
Now i get only 1 long string ofcourse. How can i fix this? I want to fill the 2 lists in the view. But #Model.Actions.Type.Add() doesn't work.
I switched away from using stringify to using postify a while ago which I've personally found better to work with as it works with MVC's default model binding. (Readme)
Example usage:
var data = {Type: [], Contact: []};
for (var i = 1; i <= 5; i++) {
data.Type.push("Type " + i.toString());
data.Contact.push("Contact" + i.toString());
}
$.post('someurl', $.postify(data), function(response) {
// process response
});