Use javascript variable in c# - javascript

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)

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. *#

Order dropdown list in ASP.Net mvc 5 application

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>
}

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.

How to get checkbox selected value and pass to controller in asp.net mvc 4

I am trying to get the selected checkboxes value
this are my models,
public class VehicleViewModel : Vehicle
{
[Display(Name = "Vehicle Type")]
[Required( ErrorMessage = "{0} is required.")]
public string VehicleTypeName { get; set; }
[Display(Name = "Location")]
[Required(ErrorMessage = "{0} is required.")]
public string LocationName { get; set; }
public IEnumerable<AssignProductsViewModel> AssignedProducts { get; set; }
}
public class AssignProductsViewModel
{
public long ProductID { get; set; }
public string ProductName { get; set; }
}
here's my razor view
#foreach (var item in Model.AssignedProducts)
{
<tr>
<td>
<input type="checkbox" value ="#item.ProductID"/>
</td>
<td>
#Html.DisplayFor(model => item.ProductName)
</td>
</tr>
}
and here's my controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult NewVehicle(VehicleViewModel vehicleViewModel, string selected)
{
//Do something with the string here
return View();
}
I know I need to pass the selected check boxes value to a string using javascript and pass the string to a controller. But i have no idea how to do it since I'm a newbie in javascript and MVC.
Based on the comments that an ajax post is not required, your AssignProductsViewModel requires an additional property to bind the checkboxes
public class AssignProductsViewModel
{
public long ProductID { get; set; }
public string ProductName { get; set; }
public bool IsSelected { get; set; } // add this
}
In the view, use a for loop or a custom EditorTemplate to render the collection do the controls are correctly named with indexers. A foreach loop generates duplicate id (invalid html) and name attributes (cannot be bound to a collection)
#model VehicleViewModel
#using(Html.BeginForm())
{
// controls for VehicleTypeName, LocationName
for(int i = 0; i < Model.AssignedProducts.Count; i++)
{
#Html.HiddenFor(m => m.AssignedProducts[i].ProductID) // ditto for ProductName if you want it on postback
#Html.CheckBoxFor(m => m.AssignedProducts[i].IsSelected)
#Html.LabelFor(m => m.AssignedProducts[i].IsSelected, Model.AssignedProducts[i].ProductName)
}
....
}
and post back to
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult NewVehicle(VehicleViewModel model)
{
// model.AssignedProducts contains the collection with a value indicating if the product has been selected
}
Alternatively, you can use an EditorTemplate for type of AssignProductsViewModel to render the collection
In /Views/Shared/EditorTemplates/AssignProductsViewModel.cshtml
#model AssignProductsViewModel
#Html.HiddenFor(m => m.ProductID) // ditto for ProductName if you want it on postback
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m..IsSelected, Model.ProductName)
and in the main view
#model VehicleViewModel
#using(Html.BeginForm())
{
// controls for VehicleTypeName, LocationName
#Html.EditorFor(m => m.AssignedProducts)
<input type="submit" />
}

Return a Javascript array to action

Here's my problem:
i have a JS array that i want to pass it to an action and then render that action's View.
this is my array and i fill it Using Jquery like so :
var factorlist = [];
factorlist.push({ ID: data.ID, Name: data.Name, number: data.number, SingelPrice: data.SingelPrice, TotalPrice: data.TotalPrice })
(data come from an AJAX Call)
then i put a hidden input element in my page to put my array in it and send it with a submit.
here is hidden input and submit button :
<input type="submit" id="input" name="input" />
<input type="hidden" id="list" name="list"/>
This is how i send it :
$('form').submit(function (event) {
$('#list').val(JSON.stringify(factorlist));
});
and this is the action that i'm sending the array to :
public ActionResult PrePayment(List<Order> list)
{
return View(list);
}
and my order class :
public class Order
{
public int ID { get; set; }
public string Name { get; set; }
public int number { get; set; }
public float SingelPrice { get; set; }
public float TotalPrice { get; set; }
}
**Now the thing is i get and empty list in action not null...what is the problem and is there any other way to do this? **
The default MVC data binding will not work for you in this case, you have to deserialize your values manually:
var js = new JavaScriptSerializer();
list = (Order[])js.Deserialize(Request.Form["list"], typeof(Order[]));
To avoid doing this every time you can register a Custom Model Binding for that type too, check an example in http://www.codeproject.com/Articles/605595/ASP-NET-MVC-Custom-Model-Binder
You should use Json instead of JS array. More details http://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult(v=vs.118).aspx
if i understand you right, you want to post your js array from form to controller action, so basing on this article there is a solution:
$('form').submit(function (event) {
$(factorlist).each(function (i, el) {
$('form').append($('<input />', {
type: 'hidden',
name: 'list[' + i + '].ID',
value: el.ID
}));
// and so on for each your of objects property
});
});
More correct way is to do it using ajax and redirect on success callback.

Categories