my model code
public class viewCase
{
public List<string> lstCategory { get; set; }
public DataTable dtWrkTsk { get; set; }
}
my controller code
string query = "SELECT WorkFlowID,Subject,Category FROM CMSTasksWorkFlow"
objcase.dtWrkTsk = objdataclas.ExecuteDataTable(query);
return View("../ViewCases/CasesScreen",objcase);
my cshtml code
function getCaption() {
var cat= $("#layout option:selected").text(); //variable for select condition
var arr = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(
Model.dtWrkTsk.Select("Catagory='" + cat + "'") )); //<- error here
}
its giving me error 'cat ' does not exist in current context
and if i try
function getCaption() {
var cat= $("#layout option:selected").text(); //variable for select condition
var arr = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(
Model.dtWrkTsk.Select("Catagory='" +#<text> cat </text> + "'") ));} //<- error here
CS1660: Cannot convert lambda expression to type 'string' because it
is not a delegate type
<div id="addTask" class="modal fade " aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content round">
<div class="modal-header"><h4>New Task </h4></div>
<div id="tbody" class="modal-body" style="height:20%">
#Html.DropDownList("layout", Model.lstCategory.Select(m => new SelectListItem { Text = m, Value = m }), "All", new { onclick = "getCaption()" })
<div id="dtask" style="width: 80%; overflow: scroll; ">
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-primary" >OK</button>
<button type="button" data-dismiss="modal" class="btn">Cancel</button>
</div>
</div>
</div>
</div>
i am trying to keep datatable disconnected from server so whenever user changes value in Html.DropDownList function getCaption() is called
i only need select condition in datatable where i select category with javascript varible passing
how do i pass my javascript variable in datatable.select
The #Html.Raw() in var arr = #Html.Raw(...) is razor code which is parsed on the server before its sent to the view. It includes a .Select() query that uses a javascript variable which does not exist at that point - its not in scope.
You need to assign the collection to a javascript variable, and the filter the resulting array in javascript based on the selected option.
The following assumes dtWrkTsk is a collection of a model containing a property string Category, and you want to filer the collection to return only objects whose Category value matches the selected option
#Html.DropDownList("layout", Model.lstCategory.Select(m => new SelectListItem { Text = m, Value = m }), "All")
or
#Html.DropDownList("layout", new SelectList(Model.lstCategory), "All")
<script>
// Assign the collection to a javascript array
var arr = #Html.Raw(Json.Encode(Model.dtWrkTsk))
$('#layout').change(function() {
var selectedCategory = $(this).val();
// Return all objects in the collection that match
var result = $(arr).filter(function(index, item) {
return item.Category === selectedCategory;
});
.... // do something with the results
});
</script>
Additional suggest reading - Unobtrusive JavaScript
Related
I have a view with a modal pop-up that displays "parameters" or rather data from a Dictionary being passed to the front end. With my current JS, it appears my function will only deserializing one key and value at a time. However, I need to edit the function so that It can deserialize more than one key and value, if the dictionary is passing in more than one key and value..
Below is my code. If you want to know more about the back end please let me know.
Controller is returning:
var parameters = new Dictionary<string, string>();
return Json(parameters, JsonRequestBehavior.AllowGet);
To reiterate, parameters is a Dictionary that can have either one key/value OR it could hold multiple key/value pairs.
JS:
$("button[name='paramsBtn']").click(function () {
/* Grabs ID from col selected */
var $col = $(this).closest('.row').find('.requestId');
var jobRequestId = $col.data('id');
$.ajax({
url: '#Url.Action("JobPollerParameters", "Tools")',
data: { "jobRequestId": jobRequestId},
success: function (results) {
$modal = $('#paramsModal');
$modal.modal("show");
var arr = results;
//loop through arr created from dictionary to grab key(s)
for (var key in arr) {
if (arr.hasOwnProperty(key)) {
var myKey = key;
}
}
var name = myKey;
var value = results[myKey];
$('#modalName').text(name);
$('#modalMessage').text(value);
}
});
});
Here is the modal:
<div class="modal fade" id="paramsModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header modal-header-primary">
<a class="btn btn-xs btn-primary pull-right" data-dismiss="modal" aria-label="Close"><span class="glyphicon glyphicon-remove"></span></a>
<h4 class="modal-title" id="modalTitleText">Job Parameters</h4>
</div>
<div class="modal-body">
<div class="list-group">
<div class="row list-group-item list-group-item-heading container divTableHeading" style="width:inherit; margin-bottom:0px;">
<div class="col-md-6 font-weight-bold"> Parameter: </div>
<div class="col-md-6 font-weight-bold"> Value: </div>
</div>
<div class="row list-group-item container" style="width:inherit;">
<div class="col-md-6 text-break" id="modalName"></div>
<div class="col-md-6 text-break" id="modalMessage"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
This line is confusing:
var myKey = key;
After the loop completes, myKey will be equal to the last index in your array, so 2 if results had length 3.
So, name will equal 2 and value will be equal to the last element in results
Maybe you're looking for something like this, since results is {string, string}:
// sample results array from server
var arr = ["val1", "val2", "val3"];
var displayString = "";
for (var key in arr) {
if (arr.hasOwnProperty(key)) {
displayString += arr[key] + ","; // note, there will be a trailing comma
}
}
console.log(displayString);
See the comments below, essentially you arent doing all of the work inside the loop thus your function appears to produce 1 variable (the last one in the dictionary)
$("button[name='paramsBtn']").click(function () {
/* Grabs ID from col selected */
var $col = $(this).closest('.row').find('.requestId');
var jobRequestId = $col.data('id');
$.ajax({
url: '#Url.Action("JobPollerParameters", "Tools")',
data: { "jobRequestId": jobRequestId},
success: function (results) {
$modal = $('#paramsModal');
$modal.modal("show");
var arr = results;
//loop through arr created from dictionary to grab key(s)
for (var key in arr) {
if (arr.hasOwnProperty(key)) {
var myKey = key;
}
}
//Move these variables inside the loop. you are setting them once
//they are in essence being set to the last value in the dictionary
var name = myKey;
var value = results[myKey];
$('#modalName').text(name);
$('#modalMessage').text(value);
}
});
});
I'm trying to do a sort of invoicing system, and the html looks like this:
<invoice>
<headers>
<div date contenteditable>15-Jan-2020</div>
<div buyer contenteditable>McDonalds</div>
<div order contenteditable>145632</div>
</headers>
<item>
<div name contenteditable>Big Mac</div>
<div quantity contenteditable>5</div>
<div rate contenteditable>20.00</div>
</item>
<item>
<div name contenteditable>Small Mac</div>
<div quantity contenteditable>10</div>
<div rate contenteditable>10.00</div>
</item>
</invoice>
<button>Loop</button>
I need to loop through each <invoice> and get details from <headers> and <item>, so the end results look like this.
date : 15-Jan-2020 buyer : McDonalds order:145632
item : Big Mac quantity : 5 rate : 20.00
item : Small Mac quantity : 10 rate : 10.00
I plan on sending this data as json to a PHP script for processing.
The problem is, <headers>,<items> wont be the only containers in each invoice. There could be <address>,<transporter> etc. but they'll all be inside each <invoice>.
With that being the case, how can I loop through each container and get it's data?
Here's the jQuery I was attempting:
var button = $("button")
button.on("click", function() {
$('invoice').each(function() {
alert('It works');
});
});
Fiddle here
You can loop through div and use data-attribute for name label as below
$('invoice>headers>div, invoice>item>div').each(function(index,item) {
console.log($(this).attr('data-name'), $(this).text());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<invoice>
<headers>
<div date contenteditable data-name="date">15-Jan-2020</div>
<div buyer contenteditable data-name="buyer">McDonalds</div>
<div order contenteditable data-name="order">145632</div>
</headers>
<item>
<div name contenteditable data-name="name">Big Mac</div>
<div quantity contenteditable data-name="quantity">5</div>
<div rate contenteditable data-name="rate">20.00</div>
</item>
<item>
<div name contenteditable data-name="name">Small Mac</div>
<div quantity contenteditable data-name="quantity">10</div>
<div rate contenteditable data-name="rate">10.00</div>
</item>
</invoice>
$('headers > div, item > div').each(function(item) {
console.log('item');
});
It seems your HTML isn't valid HTML. The spec doesn't define elements like <invoice>, <headers> and <item>. Besides that, attributes on elements almost always resemble key-value pairs, meaning you should declare your name, buyer, order, quantity and rate attributes as values of existing attributes. The contenteditable attribute is a boolean attribute which is OK to be left as it currently is.
Here is a fixed and working example:
var button = $('#read-invoice');
// readLine :: [String] -> (HTMLElement -> String)
function readLine(fields) {
return function (el) {
return fields.reduce(function (txt, field) {
var data = $('.' + field, el).text();
return txt === ''
? field + ': ' + data
: txt + '; ' + field + ': ' + data
}, '');
}
}
// readBlock :: { (HTMLElement -> String) } -> (HTMLElement -> String)
function readBlock(readers) {
return function (el) {
var rtype = el.className;
if (typeof readers[rtype] === 'function') {
return readers[rtype](el);
}
return '';
}
}
// autoRead :: HTMLElement -> String
var autoRead = readBlock({
headers: readLine(['date', 'buyer', 'order']),
item: readLine(['name', 'quantity', 'rate'])
// ... address, etc.
});
button.on('click', function () {
var result = $('.invoice').
children().
toArray().
reduce(function (txt, el) {
var line = autoRead(el);
return line === ''
? txt
: txt + line + '\n';
}, '');
console.log(result);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="invoice">
<div class="headers">
<div class="date" contenteditable>15-Jan-2020</div>
<div class="buyer" contenteditable>McDonalds</div>
<div class="order" contenteditable>145632</div>
</div>
<div class="item">
<div class="name" contenteditable>Big Mac</div>
<div class="quantity" contenteditable>5</div>
<div class="rate" contenteditable>20.00</div>
</div>
<div class="item">
<div class="name" contenteditable>Small Mac</div>
<div class="quantity" contenteditable>10</div>
<div class="rate" contenteditable>10.00</div>
</div>
</div>
<button id="read-invoice">Loop</button>
JS explanation
The function readLine takes an Array of Strings, where each String resembles the class name of one of the inner <div> elements. It returns a function that's waiting for a "block" element (like <div class="headers">) and reads the contents of it's contained <div>'s into a single String. Let's call the returned function a reader.
The readBlock function takes an Object of reader functions and returns a function taking a "block" element. The returned function determines which type of "block" it received and calls the matching reader function with the element as argument. If no reader matches the block type, it returns the empty String.
In the end, autoRead becomes a single function taking in a whole "block" element and returning all of it's contents as a line of text.
The button click handler looks up the <div class="invoice"> element, traverses it's DOM tree down to it's child elements (our "block" elements) and passes each "block" to autoRead, building up a result String. The final result is logged to the console.
Extending
To add new types of "block"s, simply define a new reader for it and add it to the Object passed to readBlock. For example, to add an <div class="address"> reader that reads "name", "street", "zip" and "city" infos:
var autoRead = readBlock({
headers: readLine(['date', 'buyer', 'order']),
item: readLine(['name', 'quantity', 'rate']),
address: readLine(['name', 'street', 'zip', 'city']) // <<< new
});
Extending the fields a certain reader reads is also simple, just add the name of the field to read:
var autoRead = readBlock({
headers: readLine(['date', 'buyer', 'order']),
item: readLine(['name', 'quantity', 'rate', 'currency']) // <<< added "currency"
});
First time with MVC5 and Telerik... I am reading Active Directory and getting all the security groups to display in a TreeView. After an Admin is done selecting the Roles he/she shall press the Save Groups button and then the javascript is supposed to get all nodes and pass them to the controller. The controller will save to the database. I need to know how to access the datacontext for a given node. After I get the data context I can proceed to get all of the nodes context and pass it to the controller.
Kendo Treeview and Buttons:
#{
ViewBag.Title = "Configure";
}
#model IEnumerable<CMDB.Web.Models.AdminGroups>
<div>
<input id="save" type="button" value="Save Groups" onclick="SaveData()" />
<input id="return" type="button" value="Return" onclick="location.href='#Url.Action("Index", "Admin")'" />
#(Html.Kendo().TreeView()
.Name("treeview")
.Checkboxes(checkboxes => checkboxes
.Name("checkedFiles")
.CheckChildren(true)
)
.Events(events => events.Check("onCheck"))
.DataTextField("Name")
.AutoScroll(true)
.DataSource(source => source
.Model(model => model.Id("id").HasChildren("hasChildren"))
.Read(read => read.Action("GetActiveDircetoryGroups", "Configure"))
)
)
</div>
Javascript:
<script type="text/javascript" >
//show checked node IDs on datasource change
function onCheck() {
var treeView = $("#treeview").data("kendoTreeView");
var id = treeView.dataItem(e.node);
}
function SaveData() {
var AllSelectedNodes = new Array();
AllSelectedNodes = ($("#treeview .k-item input[type=checkbox]:checked").closest(".k-item"));
alert(AllSelectedNodes.join('\n'));
var myApiUrl = '#Url.HttpRouteUrl("DefaultAPI", new { controller = "AdminValues", action = "SaveSelectedAdmins"})';
var movies = $.ajax({
url: myApiUrl,
type: 'POST',
data: AllSelectedNodes
});
}
</script>
Controller:
[HttpPost]
public void SaveSelectedAdmins(IEnumerable<CMDB.Web.Models.AdminGroups> ag)
{
string Sids = string.Empty;
foreach (var s in ag)
{
var pc = new PrincipalContext(ContextType.Domain, "", "");//blank for security purposes
GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, IdentityType.Guid, s.id.Value.ToString());
if (s.id.Value.ToString() == gp.Guid.Value.ToString())
{
Sids = Sids + "," + gp.Sid;
}
}
using (var ctx = new Data.DBContext())
{
var d2 = (from d in ctx.Set<Entities.Config>()
where d.Property == "str"
select d).SingleOrDefault();
d2.Value = Sids;
ctx.SaveChanges();
}
}
Using $.post instead of $.ajax fixed the issue.
I have a listbox in view.
This Listbox use template
Listbox
<div id="UsersLoad" style="width: 50%">
#Html.EditorFor(i => i.Users, "UsersForEdit")
</div>
Template UserForEdit (Part of the code)
#model string[]
#{
if (this.Model != null && this.Model.Length > 0)
{
foreach(var item in this.Model)
{
listValues.Add(new SelectListItem { Selected = true, Value = item, Text = item });
}
}
else
{
listValues = new List<SelectListItem>();
}
}
<div class="field-#size #css">
<h3>#Html.LabelFor(model => model):</h3>
#Html.ListBoxFor(model => model, listValues, new { id = id })
</div>
In another view div "Users" is called.
function LoadUsersCheckBox() {
$("#UsersLoad").load('#Url.Action("LoadUsers", "User")' + '?idUser=' + idUser);
}
LoadUsers Controller
public JsonResult LoadUsers(int? idUser)
{
var users = Service.GetSystemUsers(idUser);
var model = users.Select(x => new
{
Value = x,
Description = x
});
return this.Json(model, JsonRequestBehavior.AllowGet);
}
The controller method returns what I want.
But instead of it select the items in the listbox it overwrites the listbox with only the text of found users.
How to mark the items in the listbox on the function LoadUsersCheckBox?
Sorry for my bad English
The jQuery load() method "loads data from the server and places the returned HTML into the matched element." Note the words "the returned HTML". See http://api.jquery.com/load/
To select existing items, you should try get() instead (http://api.jquery.com/jQuery.get/). In the success callback handler, you will need to parse the returned data to an array. Then use an iterator to go over the items in the listbox, and if they exist in the parsed array, mark them as selected. Something like:
$.get("action url", function(data) {
var users = $.parseJSON(data);
$("#UsersLoad option").each(function() {
var opt = $(this),
value = opt.attr("value");
opt.removeAttr("selected");
if (users.indexOf(value) > -1) {
opt.attr("selected", "selected");
}
});
});
So, I have been bashing my head against the desk for a day now. I know this may be a simple question, but the answer is eluding me. Help?
I have a DropDownList on a modal that is built from a partial view. I need to handle the .Change() on the DropDownList, pass the selected text from the DropDownList to a method in the controller that will then give me data to use in a ListBox. Below are the code snippets that my research led me to.
all other controls on the modal function perfectly.
Can anyone see where I am going wrong or maybe point me in the right direction?
ProcessController
// I have tried with [HttpGet], [HttpPost], and no attribute
public ActionResult RegionFilter(string regionName)
{
// Breakpoint here is never hit
var data = new List<object>();
var result = new JsonResult();
var vm = new PropertyModel();
vm.getProperties();
var propFilter = (from p in vm.Properties
where p.Region == regionName && p.Class == "Comparable"
select p).ToList();
var listItems = propFilter.ToDictionary(prop => prop.Id, prop => prop.Name);
data.Add(listItems);
result.Data = data;
return result;
}
Razor View
#section scripts{
#Scripts.Render("~/Scripts/ui_PropertyList.js")
}
...
<div id="wrapper1">
#using (Html.BeginForm())
{
...
<div id="fancyboxproperties" class="content">
#Html.Partial("PropertyList", Model)
</div>
...
<input type="submit" name="bt_Submit" value="#ViewBag.Title" class="button" />
}
</div>
Razor (Partial View "PropertyList.cshtml")
...
#{ var regions = (from r in Model.Properties
select r.Region).Distinct(); }
<div>
<label>Region Filter: </label>
<select id="ddl_Region" name="ddl_Region">
#foreach (var region in regions)
{
<option value=#region>#region</option>
}
</select>
</div>
// ListBox that needs to update after region is selected
<div>
#Html.ListBoxFor(x => x.Properties, Model.Properties.Where(p => p.Class == "Comparable")
.Select(p => new SelectListItem { Text = p.Name, Value = p.Id }),
new { Multiple = "multiple", Id = "lb_C" })
</div>
...
JavaScript (ui_PropertyList.js)
$(function () {
// other events that work perfectly
...
$("#ddl_Region").change(function () {
$.getJSON("/Process/RegionFilter/" + $("#ddl_Region > option:selected").attr("text"), updateProperties(data));
});
});
function updateProperties(data, status) {
$("#lb_C").html("");
for (var d in data) {
var addOption = new Option(data[d].Value, data[d].Name);
addOption.appendTo("#lb_C");
}
}
The callback function passed to your $.getJSON method is wrong. You need to pass a reference to the function, not to invoke it.
Try this:
$.getJSON("/Process/RegionFilter/" + $("#ddl_Region > option:selected").text(), updateProperties);
Also, in order to get the text of the selected drop-down option, you need to use the text() function:
$("#ddl_Region > option:selected").text()
See Documentation