I have controller where I send role parameter as true or false to js
Controller (relevant code):
public ActionResult GetForEdit()
{
var userRole = User.IsInRole("SuperAdmin");
#ViewBag.Role = userRole;
return Content(result, "application/json");
}
There I get true or false into #Viewbag
Ajax to call controller:
function GetModulLogWasteForEdit() {
debugger;
currentId = 0;
var manifest = $('#manifest').val();
$('#save').removeClass('hidden');
try {
$(function () {
$.ajax({
cache: false,
type: "get",
dataType: "json",
url: "/Log/GetForEdit", // controller
data: { manifest: manifest },
contentType: "application/json; charset=utf-8",
success: onGetModulLogWasteSuccess,
error: function (response) {
ErrorMessage("Error", GetTextError(response));
}
});
});
} catch (e) {
ErrorMessage("Error", e.message);
}
}
and now I populate kendo Grid to show fields, and there is where I want to use my viewbag so:
function onGetModulLogWasteSuccess(response) {
var role = '#ViewBag.Role'; // there I get my role bool
$("#lstInfo").kendoGrid({....
{
field: "", title: "Actions", width: "120px", hidden: role,
template: function (item) {
var id = item.Id;
var dropbox = "<div><div class='btn btn-danger'><a class='light' href='javascript:RemoveLogWaste(" + id + ");' role='button'><i class='fa fa-pencil-square-o'></i> Delete</a></div></div>";
return dropbox;
}
As you can see I use hidden:role parameter, but it always come true, when controller get it to false it hidden field too, Help is very appreciated. Regards
Update:
As Stephen answer, I change my controller to:
public ActionResult GetForEdit(string manifest)
{
string result = string.Empty;
var userRole = User.IsInRole("SuperAdmin");
try
{
result = new JavaScriptSerializer().Serialize(LogWasteModule.GetForEdit(manifest));
}
catch (Exception)
{
throw;
}
return Json(new
{
result,
role = userRole,
JsonRequestBehavior.AllowGet
});
}
GetForedith class:
public static List<LogEdit_Result> GetForEdit(string manifest)
{
var result = new List<LogEdit_Result>();
using (var context = new EF.A())
{
result = context.LogEdit(manifest).ToList();
}
return result;
}
But I get
his request has been blocked because sensitive information could be
disclosed to third party
You can't access the ViewBag from client-side javascript.
It is only available server-side(i.e. in your View/cshtml).
In order to do what you are trying to do, you will need to put the userRole value into the "result" that you are returning and then you will have it client-side, i.e.
public ActionResult GetForEdit()
{
var userRole = User.IsInRole("SuperAdmin");
// ...fill result (not shown)
return Json(new {
result = result,
role = userRole
}, JsonRequestBehavior.AllowGet);
}
And then
function onGetModulLogWasteSuccess(response) {
var role = response.role;
// response.result contains the "result" var from the server action.
$("#lstInfo").kendoGrid({....
}
The reason your role var is always true is because the string '#ViewBag.Role' is really the string '#ViewBag.Role' NOT the contents of the ViewBag(which again is not available client-side), and this string is truthy(evaluates as true when you ask it to be a boolean).
After Question Updated
Change your action to
public ActionResult GetForEdit(string manifest)
{
string result = string.Empty;
var userRole = User.IsInRole("SuperAdmin");
try
{
result = LogWasteModule.GetForEdit(manifest);
}
catch (Exception)
{
throw;
}
return Json(new
{
result = result,
role = userRole,
}, JsonRequestBehavior.AllowGet);
}
because
you shouldn't need to manually serialize your result as Json() will do it
the syntax of your Json(new...) is wrong: you need to use "field = value" syntax, NOT just "value" and the AllowGet needs to be a parameter to Json() NOT a value you add to the object.
Related
I have a MVC, multiple select DropDownList that populates the Select Items from a SelectListItem model.
#Html.DropDownList("EmployeeStatuses", (IEnumerable<SelectListItem>)ViewBag.EmployeeStatuses, new { multiple = "multiple", style = "width: 100%;", #class = "select2", onchange = "UpdateEmployeeStatusFilter()", id = "employee-status-type" })
When the user selects or unselects items from the DropDownList, I want to run a method in my controller that will filter the data in the view. This is done with the onChange event UpdateEmployeeStatusFilter().
<script type="text/javascript">
function UpdateEmployeeStatusFilter() {
var value = $('#employee-status-type').val();
console.log(value);
var a = ["X", "Y", "Z"];
console.log(a);
$.ajax({
type: 'POST',
url: '#Url.Action("SearchEmployee", "Employee")',
data: { valueMember: value },
dataType: 'json',
traditional: true,
success: function (msg) { alert(msg) }
});
};
</script>
When I debug the script, I am able to get the value of value and write that to the console window. When the controller method is called, the value is null.
public IActionResult SearchEmployee(string itemsSelected)
{
// Do Stuff with itemsSelected
return RedirectToAction("Index");
}
My question is how do I get that value into my controller?
I am not sure if this code is relevant or not, but I will include it for clarity.
public IActionResult Index()
{
// Get Employment Statuses
IEnumerable<SelectListItem> statuses = _mockDataRepository.GetEmployeeStatuses().Select(c => new SelectListItem
{
Value = c.ValueMember,
Text = c.DisplayMember,
Selected = c.ValueMember == "AC"
});
ViewBag.EmployeeStatuses = statuses;
}
public class SelectListItem
{
[Key]
public string ValueMember { get; set; }
public string DisplayMember { get; set; }
public int SortOrder { get; set; } = 0;
}
Name mismatch. The SearchEmployee() action method has itemsSelected input parameter. Therefore set the same parameter name in the .ajax call:
data: { itemsSelected: value },
I have a model with the following property in my MVC C# solution
public class RegistrationRequirementModel
{
public string LoadIntent { get; set; }
public string Francophone { get; set; }
public string Gender { get; set; }
public RegistrationRequirementModel(L09RegistrationRequirement requirement)
{
LoadIntent = requirement.LoadIntent;
Francophone = requirement.Francophone;
Gender = requirement.Gender;
}
}
In my javascript I can call the model and display the data, however when it comes to using some computed function that is where it fails.
Javascript
var registrationRequirementModel = {
frenchData: ko.observable(""),
genderData: ko.observable(""),
loadIntentData: ko.observable(""),
isMissingData: ko.computed(function () {
if (this.frenchData() == "") { return true };
if (this.genderData() == "") { return true };
if (this.loadIntentData() == "") { return true };
return false;
},this),
}
$(document).ready(function () {
ko.applyBindings(registrationRequirementModel, document.getElementById("RegistrationSurveyContent"));
$.ajax({
url: getStudentRegRequirementsUrl,
type: "GET",
contentType: jsonContentType,
dataType: "json",
success: function (data) {
if (!account.handleInvalidSessionResponse(data)) {
registrationRequirementModel.frenchData(data.Francophone);
registrationRequirementModel.genderData(data.Gender);
registrationRequirementModel.loadIntentData(data.LoadIntent);
}
},
error: function (jqXHR, textStatus, errorThrown) {
if (jqXHR.status != 0)
$('#notificationHost').notificationCenter('addNotification', { message: "Unable to retrieve registration requirement.", type: "error" });
}
});
});
Html
<table style="width:100%">
<tbody>
<tr>
<td data-bind="text: loadIntentData"></td>
<td data-bind="text: frenchData"></td>
<td data-bind="text: genderData"></td>
</tr>
</tbody>
</table>
The purpose is to show html if there is missing data. However when I activate this code, the computed column keep saying the frenchData is not a function. My point would be able to use in my html data-bind="visible: isMissingData". but unfortunately. I can event read from my data.
This is my call to the api
public async Task<JsonResult> GetRegistrationRequirementAsync()
{
string StudentID = CurrentUser.PersonId;
try
{
var requirement = await ServiceClient.L09GetRegistrationRequirementAsync(StudentID);
RegistrationRequirementModel registrationRequirementModel = new RegistrationRequirementModel(requirement);
return Json(registrationRequirementModel, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{}
}
The frenchData is not a function console error stems from the way that the KnockoutJS ViewModel is set up. In essence, the computed function isMissingData below the normal observables has a new inner scope context of this that does not reflect the same outer scope of the registrationRequirementModel object.
To work around this, you should switch from using an object literal to a constructor function so that you can assign this ViewModel scope to a self/that variable which alleviates scope issues. Then instantiate your newly stored ViewModel via KO Apply Bindings that you will now have access to after AJAX success:
function registrationRequirementModel() {
var self = this;
self.frenchData = ko.observable("");
self.genderData = ko.observable("");
self.loadIntentData = ko.observable("");
self.isMissingData = ko.computed(function() {
if (self.frenchData() == "") {
return true
};
if (self.genderData() == "") {
return true
};
if (self.loadIntentData() == "") {
return true
};
return false;
}, this);
}
$(document).ready(function() {
var vm = new registrationRequirementModel();
ko.applyBindings(vm, document.getElementById("RegistrationSurveyContent"));
// replace with endpoint
var jsonData = {
Francophone: "Francophone",
Gender: "Male",
LoadIntent: "LoadIntent"
};
if (handleInvalidSessionResponse(jsonData)) {
vm.frenchData(jsonData.Francophone);
vm.genderData(jsonData.Gender);
vm.loadIntentData(jsonData.LoadIntent);
}
});
function handleInvalidSessionResponse(data) {
if (typeof data !== "undefined") return true;
return false;
}
Below is a mock JSFiddle of the scenario
http://jsfiddle.net/ajxrw39m/3/
When you're defining your viewmodel, this does not point to the newly created object, it points to whatever this is in the context you're creating it (probably window).
var vm = {
computedUsingThis: ko.computed(function() {
return this;
}, this)
}
console.log(
vm.computedUsingThis() === vm, // false
vm.computedUsingThis() === window // true
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
There are many ways to circumvent the issue. You can use a constructor function and the new keyword, or create a factory method for the viewmodel:
const VM = () => {
const a = ko.observable("a");
const b = ko.observable("b");
const ab = ko.pureComputed(
() => a() + b()
);
return { a, b, ab };
}
const vm = VM();
vm.ab.subscribe(console.log);
setTimeout(
() => {
vm.a("A");
},
500
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
I have the following BreezeController
[BreezeController]
public class BreezeController : ApiController
{
readonly EFContextProvider<MyContext> _ContextProvider = new EFContextProvider<MyContext>();
[HttpGet]
public string Metadata()
{
return _ContextProvider.Metadata();
}
....other controllers exposing model types....
[HttpGet]
public IQueryable<Size> Sizes()
{
return _ContextProvider.Context.Sizes;
}
}
which I access from the client from my DataContext.js with this
var getSizes = function (sizesObservable, modelId) {
var query = entityQuery.from('Sizes').where('ID', '==', modelId)
.orderBy('sortOrder').orderBy('size').orderBy('enteredDate');
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
if (sizesObservable) {
var intialValues = { size: ' Select a Size', sizeID: breeze.core.getUuid(), modelID: modelId };
createNullo(entityNames.size, 'Size', intialValues);
sizesObservable(data.results);
}
log('Retrieved [Sizes] from remote data source', data, false);
}
};
All of this works just fine. I would like to add another route to my controller that has some specialized filtering done on the server.
[HttpGet]
public IQueryable<Size> GetUniqueSizes()
{
return //custom filtering logic here.
}
with the following javascript in my DataContext.js
var getUniqueSizes = function (sizesObservable, modelId) {
var query = entityQuery.from('GetUniqueSizes').where('modelID', '==', modelId).where('Approved', '==', 'True')
.orderBy('sortOrder').orderBy('size').orderBy('enteredDate');
return manager.executeQuery(query)
.then(querySucceeded);
function querySucceeded(data) {
if (sizesObservable) {
var intialValues = { size: ' Select a Size', sizeID: breeze.core.getUuid(), modelID: modelId };
createNullo(entityNames.size, 'Size', intialValues);
sizesObservable(data.results);
}
log('Retrieved [Sizes] from remote data source', data, false);
}
};
but when I do this I get the following error on the client
TypeError: Cannot read property 'toODataFragment' …localhost:63144/scripts/breeze.debug.js:12728:23)
Why is this route not working?
try changing the multiple orderBy statements to a multiple property sort.
.orderBy('sortOrder,size,enteredDate')
likewise, you might have better luck if you combine the where clauses.
I have some JS which is passing (or trying to pass) a model and a string to an MVC controller.
The JS code is:
$.ajax({
url: self.ajaxValidationUrl,
type: "POST",
data: { model: $("form").serialize(), stepList: thisStepList },
async: false,
success: function(errors) {
console.log("Errors...");
if (errors.length > 0) {
anyServerError = true;
}
for (var i = 0; i < errors.length; i++) {
console.log(errors[i].ErrorMessage);
self.errorList += "<li>" + errors[i].ErrorMessage + "</li>";
}
}
});
The Controller looks like this:
[HttpPost]
public ActionResult ValidateReport(MyTemplate model, string stepList)
{
var errors = model.Validate();
return Json(errors);
}
The model parameter is blank and isn't resolving to the MyTemplate object. The post parameters are coming in ok.
I have a JSONmodel binder I got from somewhere, the place has escaped me but look at this.
public class FromJsonAttribute : CustomModelBinderAttribute
{
private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();
public override IModelBinder GetBinder()
{
return new JsonModelBinder();
}
private class JsonModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
if (string.IsNullOrEmpty(stringified))
return null;
return serializer.Deserialize(stringified, bindingContext.ModelType);
}
}
}
That allows you to do this in your controller.
[HttpPost]
public ActionResult GiftsCOG([FromJson] List<GiftModel> gifts, [FromJson] string guid)
{
}
This allows you to pass JSON from javascript.
I am trying to send an object array to my controller but having some difficulties.
It is sending the array and when delivered to the controller, the object count of the array also seems OK.
But if you will look inside the objects all the attributes of the objects are null
How it can be possible?
JavaScript:
function callme(results) {
for (var i = 0; i < results.length; i++) {
var endRes = {
Id: results[i].id,
Icon: results[i].icon
};
jsonObj.push(endRes);
}
sendPackage(jsonObj);
}
function sendPackage(jsonObj) {
$.ajax({
type: "POST",
url: '../../Home/RegisterList',
data: { List: jsonObj },
cache: false,
dataType: "json",
error: function (x, e, data) {
alert(data);
}
});
}
Controller:
[HttpPost]
public JsonResult RegisterList(ICollection<DetailsModel> List)
{
foreach (var i in List) ....... // other process will be here
............................... // other process will be here
return Json(new { message = "OK" });
}
Model:
public class DetailsModel
{
public string Id { get; set; }
public string Icon { get; set; }
}
Ok I've solved the problem last night by using Newton's JSON.NET (you can get it from NuGet). I've stringified the array and recieved it as a string with the controller. Finally I used json.net to convert(deserialize) this string into a collection.
To stringify: use same code but change the data section of the json request with:
data: { List : JSON.stringify(jsonObj) }
Finally recieve it by:
using Newtonsoft.Json;
public JsonResult RegisterList(string List)
{
ICollection<DetailsModel> jsonModel = JsonConvert.DeserializeObject<ICollection<DetailsModel>>(List);
}
And voila; you have a collection named jsonModel!
Unfortunately model binding of lists is not that nice and obvious in MVC. See:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Passing the list this way works:
data: {"List[0].Id":"1", "List[0].Icon":"test"}