Order dropdown list in ASP.Net mvc 5 application - javascript

I have a dropdown and I want it to appear in a particular order where dropdown option header should come before footer. but I am not able to do so.
Helper
public static readonly string HEADER_ID = "-1000";
public static readonly string FOOTER_ID = "-1001";
CSHTML
<select id="simTextEditorSelection" onchange="ShowTextEditorBasedOnSelection();" style="float:right;">
#foreach (PageInfoMV anItemForEditor in Model.ItemContents)
{
<option value="#anItemForEditor.ItemId">#anItemForEditor.ItemDisplayText</option>
}
UI
P.S: I don't want to change the enum values of Header and footer. Please guide me.
My Attempt:
#foreach (PageInfoMV anItemForEditor in Model.ItemContents.OrderByDescending(x=>x.Id))
But it created some other issues. So, I want to avoid it.

Assume you have this class:
public class MyClass
{
public int Id { get; set; }
public int Name { get; set; }
}
In the Action you can create a SelectList from any list as followed:
public ActionResult Create()
{
var list = db.MyClass.ToList(); //or an other way to get the list of items
//you can add som more items to the list:
list.Add(new MyClass { Id=-1000, Name="Some Name" });
ViewBag.Selectlist = new SelectList(list.OrderByDescending(x=>x.Id), "Id", "Name");
return View();
}
In the View:
#{
var optionList = ViewBag.Selectlist as SelectList;
}
#Html.DropDownListFor(model => model.someProperty, optionlist, "- Select an option -")

Change your cshtml to this and you should have your wish
<select id="simTextEditorSelection" onchange="ShowTextEditorBasedOnSelection();" style="float:right;">
#foreach (PageInfoMV anItemForEditor in Model.ItemContents.OrderByDescending())
{
<option value="#anItemForEditor.ItemId">#anItemForEditor.ItemDisplayText</option>
}

Related

Using C# MVC multiple dynamic models in View

I have a View with several form that I'm using for searching and displaying the results as partial View in like SearchByNumber, SearchByVehicle, etc.
I'm trying to load view and execute search for different forms by posting link with querystring like www.example.com/Search?number=101010 from different view.
For the first form, SearchByNumber I only have one parameter, string number and i'm returning view with dynamic Model and its working like it should, but I only manage to make search for this form.
Here is my controller:
public ActionResult Index(string number)
{
return View(model: number);
}
and in the View I have:
<form id="searchbynumberform">
Search By Any Number:
<div class="input-group input-group-sm">
<input type="text" class="form-control" name="number" id="number" value="#Model">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" name="numbersearch" id="numbersearch" disabled>
Search
</button>
</span>
</div>
</form>
My Question is, if anyone can help me, How to perform search let's say on the second form where I have int type and string name parameters?
Thank You in advance...
At the moment your Model is only the search string that was entered, which seems rather incomplete. It would make a lot more sense if the Model also contained the actual search results, which after all is what the user wants to see. And then you can also add the other search properties.
The MVC approach for this is to create a (View)Model class, somewhere in your project, something like this:
public class SearchModel
{
public string Number { get; set; }
public int? Type { get; set; }
public string Name { get; set; }
public List<SearchResult> SearchResults { get; set; }
}
And then use it e.g. like this:
public ActionResult Index(string number)
{
var model = new SearchModel
{
Number = number,
SearchResults = GetByNumber(number)
};
return View(model);
}
public ActionResult IndexOther(int type, int name)
{
var model = new SearchModel
{
Type = type,
Name = name,
SearchResults = GetByTypeAndName(type, name)
};
return View(model);
}
And in your Index.cshtml:
#model SearchModel
#* You can now use Model.Number, Model.Type, Model.Name and Model.SearchResults. *#

Use javascript variable in c#

Is it possible to use js variables in c# code?
This is my model:
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public virtual ICollection<Department> Parent { get; set; }
}
And this is my cshtml:
#model List<inspinia.models.Department>
<select name="DepartmentId" class="form-control" id="Department">
#foreach (var item in Model)
{
<option value="#item.Id">#item.Name</option>
}
</select>
<script>
$(document).ready(function () {
$("#Department").on("change", function () {
var DepartmentId = $('option:selected', this).attr('value');
//the problem in the next line.
#foreach(var item in Model.Where(x=>x.ParentId==#:DepartmentId))
{
#:alert(#item.id)
}
});
});
</script>
Well I am having error when I use
Model.Where(x=>x.ParentId==#:JAVASCRIPT VARIABLE).
Is there any way to do it or I definitely have to use ajax ?
No you can't, because the javascript code's is for clientside and razor in serverside.
You have two solutions:
1- Put all departement in list(<ul>) and use JQuery for get your data on change
2- Use jquery ajax and get data directly from controller(create controller for that)

Cascading Dropdown list MVC5 using fluent nhibernate

I have read for 2 days every single question that looks like my problem on here and read multiple pages and tutorials and even watched videos and i just can't understand it or make it work...
What im trying to do is that i have 2 dropdown lists, one is "Departamentos" which you can think of it as a state and "Municipios" which you can think of it as a county. What i need and no matter what i just CAN'T make it work is that when i select a departamento ONLY the municipios from that departamento show up on the dropdown list. Im really a complete noob regarding programming and unfortunately i think i started with something way too big for me, so i' sorry if this is a basic really easy thing to do for you.
The departamento class is :
public virtual int id_departamento { get; set; }
public virtual string descripcion { get; set; }
//i specify Relationship for fluent Nhibernate to municipios since it is a 1-n
public virtual IList<Municipios> Municipios { get; set; }
The municipio class is :
public virtual int id_municipio { get; set; }
public virtual string municipio { get; set; }
public virtual int id_departamento { get; set; }//THis is the FK from Departamento
And heres my main class Sitios where i connect everything to:
This is for the Nhibernate relationships
public virtual Departamentos Departamento { get; set; }
public virtual Municipios Municipios { get; set; }
This is for the lists on that same Sitios class:
public virtual List<Departamentos> Departamentos { get; set; }
public virtual List<Municipios> municipiosLista { get; set; }
Now going to MVC this is the controller i have for the Get create where i populate the lists of Departamento and Municipio to be shown:
using (ISession session = NhibernateHelper.OpenSession())
{
var deptos = session.Query<Departamentos>().ToList();
var munis = session.Query<Municipios>().ToList();
var instanciadelacopia=new Sitios
{
Departamentos = deptos,
municipiosLista = munis
};
return View(instanciadelacopia);
}
And the create view for that specific dropdown part:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Sitios</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label class="control-label col-md-2"> Departamento </label>
<div class="col-md-10">
#Html.DropDownListFor(model => model.id_departamento, new SelectList(Model.Departamentos, "id_departamento", "descripcion"), "--Select--", new {#id = "depto"})
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2"> Municipio </label>
<div class="col-md-10">
#Html.DropDownListFor(model => model.id_municipio, new SelectList(Model.municipiosLista, "id_municipio", "municipio"), "--Select--", new { #id = "muni" })
</div>
</div>
Everything works fine since it brings me all the values for me to select from the db, where i'm stuck and can't advance is that i need a cascading dropdown for the municipios list that when i select certain departamento ONLY the municipios of THAT selected departamento show up on the list.
So for example i select departamento "atlantida" which it's ID is 1 then only the municipios which have that foreign key from Departamentos = 1 are shown which im guessing Jquery is required.
Would be really good if someone can help me with this, i feel so stressed since i just cant figure out what i need to do. Thanks
All examples i've seen are about using JSON like this one:
http://www.c-sharpcorner.com/uploadfile/4d9083/creating-simple-cascading-dropdownlist-in-mvc-4-using-razor/
but since i already have all the data available on the dropdowns i think i don't need that and instead just a plain jquery function which i cant create.
Solved it with this:
<script type="text/javascript">//Script for Cascading Dropdown
$(function () {
$('#id_departamento').change(function() {
var departmentId = $(this).val() || 0;
$.ajax({
url: '/Sitios/Municipios/',
type: 'POST',
data: { id_departamento: departmentId }, // parametro
dataType: 'json',
success: function (data) {
var options = $('#id_municipio');
$('option', options).remove(); //
options.append($('<option />').val('').text('---'));
$.each(data, function () {
options.append($('<option />').val(this.id).text(this.name));
});
}
});
});
});

ListBoxFor add data attribute to each option element

I have a MultiSelectList that I am currently using to create a ListBoxFor in my view. On my ViewModel I have an additional property on each of the items in the list that I would like to expose in the HTML for client side manipulation.
I have a checkbox above this list. When a user clicks the checkbox only data-x="true" items should show in this list. If the user does not click the checkbox, all items are shown (data-x="true" and data-x="false"). This logic is done client side each time the checkbox it changed
I am assuming the best way to do this would be to add a data-* attribute to each of the option elements. How exactly would I go about doing this? I am thinking an HTMLHelper method would be needed to extend the functionality of ListBoxfor but I am not sure where to get started, or if this is even the best way to go about this?
To be able to generate <option> elements with a data=* attribute, you would need to create you own class based on SelectListItem with additional properties for the attributes, and then generate you own HtmlHelper extension method based on the code in the System.Web.Mvc.SelectExtensions class.
A far easier way to handle this would be to pass collection you use to build the SelectList to the view, assign it to a javascript array and then use javascript/jquery to handle the checkbox .click() event and rebuild the list of options in the <select> element. In your case, it could simply be a case of hiding/showing items based on the value of the checkbox.
For example, if you have a view to select a product, and include a checkbox to limit that selection to only locally made products, your models might be
public class MyViewModel
{
public bool UseLocalProductOnly { get; set }
public int SelectedProduct{ get; set; }
public IEnumerable<SelectListItem> ProductList { get; set; }
public IEnumerable<int> LocalProducts { get; set; }
}
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsLocalProduct { get; set; }
}
and in the controller
var products = db.Products;
MyViewModel model = new MyViewModel()
{
ProductList = new SelectList(products, "ID", "Name"),
LocalProducts = products.Where(x => x.IsLocalProduct).Select(x => x.ID)
}
return View(model);
and in the view
#Html.CheckBoxFor(m => m.UseLocalProductOnly)
#Html.DropDownListFor(m => m.SelectedProduct, Model.ProductList)
<script>
var localProducts = #Html.Raw(Json.Encode(Model.LocalProducts))
var select = $('#SelectedProduct');
var options = select.children('option');
$('#UseLocalProductOnly').click(function() {
if ($(this).is(':checked')) {
// reset the selected option if it would otherwise be hidden
if ($.inArray(Number(select.val()), localProducts) === -1) {
select.val(localProducts[0]);
}
// hide options that are not local products
$.each(options, function () {
if ($.inArray(Number($(this).val()), localProducts) === -1) {
$(this).hide();
}
});
} else {
// show all options
productOptions.show();
}
});
</script>
Alternatively you could use .prop('disabled', true); (or false) to enable or disable options rather that hiding them.

How to get collection of IDs, and Selected Dropdown values passed from View's table to Controller?

So I have a checklist/task manager kind of application that basically pulls a bunch of string values from a database using a model, and then pipes it out to a view which uses a expand/collapse patterned table. The only element that an end user modifiers beyond the expand/collapse state is the dopdown list for the project status.
Rather than an update button for each row, the customer wants basically a single button on the bottom of the page which updates all the rows the user changed. So my goal is to try and create said button. As far as the View code snippet, I've tried messing around with Html.BeginForm, but haven't been able to figure out how to also capture the multiple item IDs as well:
#using (Html.BeginForm("UpdateDB", "Checklist", new { id = model.ID })) // model does not exist in this current context
{
<table id="checklistGrid" class="table table-bordered table-striped grid">
<tr>
<th>#Html.DisplayNameFor(model => model.ww)</th>
.... // more table headers
</tr>
#foreach (var group in Model.GroupBy(x => x.ww))
{
<tr class="group-header">
<td colspan="12">
<span class="h2">#group.Key</span>
</td>
</tr>
foreach (var dept in group.GroupBy(x => x.dept))
{
<tr class="dept-header">
<td colspan="12">
<span class="h4">#dept.Key</span>
</td>
</tr>
foreach (var item in dept)
{
<tr class="row-header">
<td> #Html.HiddenFor(modelItem => item.ID)</td>
<td>#Html.DisplayFor(modelItem => item.ww)</td>
.... // more table columns
<td>
#{
List<string> ddl = new List<string> { "Done", "Not Done", "N/A" };
SelectList sl = new SelectList(ddl, item.status);
#Html.DropDownList("newStatus", sl); // Added
}
</td>
<td>#Html.DisplayFor(modelItem => item.applied_by)</td>
<td>
#{
DateTime tmp;
//Check if not null, if not null convert to specified time zone
if (DateTime.TryParse(item.timestamp.ToString(), out tmp))
{
tmp = item.timestamp ?? DateTime.MinValue;
string zoneName = "India Standard Time";
var abbrZoneName = TimeZoneNames.TimeZoneNames.GetAbbreviationsForTimeZone(zoneName, "en-US");
TimeZoneInfo zoneInfo = TimeZoneInfo.FindSystemTimeZoneById(zoneName);
DateTime istTime = TimeZoneInfo.ConvertTimeFromUtc(tmp, zoneInfo);
#Html.Raw(istTime.ToString() + " (" + abbrZoneName.Generic + ")");
}
else
{
#Html.DisplayFor(modelItem => item.timestamp);
}
}
</td>
</tr>
}
}
}
</table>
<p><input type="submit" value="Save Changes" /></p>
}
<script type="text/javascript">
// Hide/Show Dept's Data on Click
$(function () {
$('.dept-header').click(function () {
$(this).nextUntil('.dept-header, .group-header').toggle();
});
});
$(function () {
$('.group-header').click(function () {
var elm = $(this);
if (elm.next().is(":visible")) {
elm.nextUntil('.group-header').hide();
} else {
elm.nextUntil('.group-header', '.dept-header').show();
}
});
});
</script>
I suspect the easier (and computationally quicker way) would to be to use Jquery + Ajax && Json attached to a button onclick at the bottom to send the collection of id and selected dropdown text to an ActionResult in the Controller (to then update the database) and then refresh on the success Ajax callback. However my Jquery/Javascript foo is weak and given the clickable 'header' type rows that expand/collapse the data rows, it's not clear to me how I would efficiently use Jquery to navigate and grab the item.IDand the selected dropdown text from each row, bundle it up, and pipe to the desired ActionResult.
So how do I send both the id and selected dropdown text of all the rows to an arbitrary ActionResult be it with Html.BeginForm or Jquery et al?
EDIT: Model for reference:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace TaskTracker.Models
{
[Table("some_update")]
public class TaskInfo
{
public int ID { get; set; }
[Display(Name = "WW")]
public int ww { get; set; }
[Display(Name = "File Name")]
public string filename { get; set; }
[Display(Name = "Dept")]
public string hsd_unit { get; set; }
[Display(Name = "Owner")]
public string owner { get; set; }
[Display(Name = "Manager")]
public string manager { get; set; }
[Display(Name = "Project")]
public string project { get; set; }
[Display(Name = "Status")]
public string status { get; set; }
[Display(Name = "Last Applied By")]
public string applied_by { get; set; }
[Display(Name = "Last Updated Time Stamp")]
public DateTime? timestamp { get; set; }
}
public class TaskInfoDBContext : DbContext
{
public DbSet<TaskInfo> TaskInfoSet { get; set; }
}
}
You have a number of problems with you view including your form controls have duplicate name attributes meaning you cannot bind to you model when you submit, duplicate id attributes which is invalid html, and your creating a dropdownist with a name that is not even a property of your model. In addition your use of queries in the view code is not good practice. All of this can be solved by using view models and generating your html correctly using for loops (not foreach loops) or a custom EditorTemplate. However, since you have indicated a preference for ajax, you can post the data by making the following changes to the view
Replace the following HtmlHelper methods
#Html.HiddenFor(modelItem => item.ID)
#Html.DropDownList("newStatus", sl)
with
#Html.HiddenFor(modelItem => item.ID, new { id = "", #class = "id" })
#Html.DropDownList("Status", sl, new { id = "", #class = "status" })
This will remove the invalid id attributes and add class names for selection. Then replace the submit button with
<button type="button" id="save">Save Changes</button>
And add the following script
var rows = $('.row-header'); // store all the table rows containing the form controls
$('#save').click(function() {
// Build an array of the values to post back
var data = [];
$.each(rows, function() {
data.push({id: $(this).find('.id').val(), status: $(this).find('.status').val() });
});
$.ajax({
url: '#Url.Action("UpdateDB", "Checklist")',
type: "POST",
data: JSON.stringify({ model: data },
traditional: true,
contentType: "application/json; charset=utf-8",
success: function(data) {
// do something?
}
})
});
Then create a model to accept the values
public class TaskInfoUpdate
{
public int ID { get; set; }
public string Status { get; set; }
}
And modify you POST method to
[HttpPost]
public ActionResult UpdateDB(IEnumerable<TaskInfoUpdate> model)
Side note: Its not clear what you mean by "and then refresh on the success Ajax callback" (what is there to refresh?). I suggest that the method return either return Json(true); if the items were successfully saved, or return Json(null); (or a HttpStatusCodeResult) if not so that you can notify the user as appropriate.

Categories