I am trying to send my toolbar's 'search textbox' value through to a WEB API action. I have searched various online solutions. However, none seem to work.
On the client-side, I have a 'KeyUp' event on the 'search textbox'. Once completed, I need to append the value to the READ.
I HAVE TRIED THE FOLLOWING (CLIENT-SIDE):
// This Fails
var value = dictionary.elements.txtDeviceSearch.val();
var url = "api/devicedataitem/search?text='" + value + "'";
dictionary.instances.gridDevices.dataSource.options.transport.read.url = url;
dictionary.instances.gridDevices.dataSource.read();
// This Fails
dictionary.instances.gridDevices.dataSource.options.transport.read.data = { text: value };
dictionary.instances.gridDevices.dataSource.read();
// This Fails
dictionary.instances.gridDevices.dataSource.read({ text: 'Work Dammit' });
THE INITIAL CALL WORKS AS EXPECTED:
This is working as expected...
#(Html.Kendo().Grid<DeviceDataItem>()
.Name("gridDevices")
.DataSource(dataSource => dataSource
.WebApi()
.Model(model =>
{
model.Id(m => m.DeviceId);
model.Field(m => m.DeviceName);
model.Field(m => m.CommunicationTechnicianId);
model.Field(m => m.CommunicationTechnicianFullName);
model.Field(m => m.MeasurementTechnicianId);
model.Field(m => m.MeasurementTechnicianFullName);
})
.Read(read => read.Url("api/devicedataitem/search?text=''").Type(HttpVerbs.Post))
)
.ToolBar(toolbar =>
{
toolbar.Template(#<text>
<div class="input-group pull-right" role="toolbar">
<span class="input-group-addon">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</span>
<input type="text" class="form-control" id='txtDeviceSearch' placeholder="Search for..." />
</div>
</text>);
})
.Deferred(true))
Now we're getting somewhere, this question is better than the other one. What I was about to say back then, before giving up is that there is a parameter called parameterMap in the JavaScript widget where you can manipulate the data which will be sent in the request to API. As stated in the docs you could try:
parameterMap: function (data, type) {
return kendo.stringify($.extend({ "text": $("#txtDeviceText").text() }, data));
}
But I don't know how to add it to the razor helper because their docs sucks too much and I can't test it. So you can try:
Adding the parameter in the initialization(which I'm not sure if works):
DataSource(dataSource => dataSource.ParameterMap("jsFunctionNameHere")
Or something like that;
Setting it in your grid after initialization:
$("#grid").data("kendoGrid").dataSource.transport.parameterMap = function() {
return { text: $("#txtDeviceText").text() };
};
Demo
I bet on 2nd option, it should work.
Give this a try:
dictionary.instances.gridDevices.dataSource.type = "aspnetmvc-ajax";
We do the same thing within our application, sending parameters to the controller action in addition to the DataSourceRequest object. With that type setting removed, I get the same behaviour you do with the parameters received with null values.
The datasource is defined with js akin to this:
this.results = new kendo.data.DataSource({
type: "aspnetmvc-ajax",
transport: {
read: {
url: "Controller/Search",
data: function () {
return {
value: "abc"
};
}
}
}
});
When read() is triggered on it, it hits the controller action like this:
public JsonResult Search([DataSourceRequest] DataSourceRequest request, string value)
So nothing out of the ordinary there but with that type removed, the value is not received. Note that this is a System.Web.MVC.Controller, not a System.Web.Http.ApiController, although I can't see how that would make a difference. It may also be that the datasource type can only effectively be set at the time it is set up (so it would go in the definition, not altered after the fact as I originally suggested) but that's just another guess. I feel your pain - this sort of thing should just work.
Well, I finally figured this one out & it was difficult. This particular answer has many facets:
It uses a GET
As such, the GET requires use of the "Model Binder Attribute"
A minor POST example is now included below...
GET - WEB API:
This works because the "Model Binder Attribute" grabs the REQUEST object & hydrates it for you. Without it, the REQUEST will always be null.
// GET: /api/DeviceDataItem/Search
[HttpGet]
public DataSourceResult Search([ModelBinder(typeof(WebApiDataSourceRequestModelBinder))] DataSourceRequest request, string search)
{
var application = (MyApplication)Application;
var provider = (DeviceDataItemProvider)application.DeviceDataItemProvider;
IQueryable<DeviceDataItem> query = provider.Query();
// No 'Where' needed
if (string.IsNullOrWhiteSpace(search))
return query.ToDataSourceResult(request);
// Where
...your WHERE logic goes here...
return query.ToDataSourceResult(request);
}
GET - MVC.Read:
Notice I am referring to a custom Page Controller object that is publicly available through the window.
.Read(read => read.Url(Url.HttpRouteUrl("DefaultApi", new { controller = "DeviceDataItem", action="Search"}))
.Type(HttpVerbs.Get)
.Data("window.pageController.on.read.gridDevices"))
GET - JavaScript:
I happen to cache my objects in a Page Controller - you will have to reference your objects (however they are built).
this.on = {
read: {
gridDevices: function () {
return {
search: dictionary.elements.txtDeviceSearch.val()
}
}
},
search: {
gridDevices: function (e) {
lazyInitGridDevices();
// Clear
dictionary.instances.gridDevices.dataSource.data([]);
dictionary.instances.gridDevices.refresh();
// Read
dictionary.instances.gridDevices.dataSource.read();
}
}
};
POST:
According to Telerik, the same approach is used for passing parameters to POST requests. However, with Web API, the second parameter cannot be added to the method signature. One possible way to address this scenario is to use a JObject to get all the data from the request and then construct a new model object using this data.
For example:
public HttpResponseMessage Post(JObject jsonData)
{
ProductViewModel product = new ProductViewModel() {
ProductName = (string)jsonData["ProductName"],
UnitPrice = (decimal)jsonData["ProductID"],
UnitsInStock = (int)jsonData["ProductName"],
Discontinued = (bool)jsonData["ProductID"]
};
string searchTerm = (string)jsonData["search"];
.............
}
Related
called by selectbox go into function 'getDepAndMan()',
there is a value taken from the selectbox (works)
calls functions in the controller 'GetDepartmentAndManager' (works)
controller returns value (works)
{Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<<>f__AnonymousType6<'string, string>>}
Result View: [0] { UserDepartament = "there is value here / string", UserManager = "there is value here / string" }
should go back to ajax and call 'succes: function (employee data)' (works)
should assign values to the fields (doesn't work)
show an alert (work)
show alert with values (doesn't work, show an alert with: undefined undefined)
View:
#(Html
.DevExtreme()
.SelectBox()
.DataSource(d => d
.Mvc()
)
.OnValueChanged("getDepAndMan")
)
#(Html.DevExtreme().TextBox()
.ID("Id_department")
.ReadOnly(true)
)
#(Html.DevExtreme().TextBox()
.ID("Id_manager")
.ReadOnly(true)
)
<script type="text/javascript">
function getDepAndMan() {
var userId = {
nazwaValueId: $("#idName").dxSelectBox("instance").option("value")
};
$.ajax({
url: "#Url.Action("GetDepartmentAndManager", "Uzytkownicy")",
type: "POST",
dataType: "json",
data: {"userId": JSON.stringify(userId)},
cache: false,
success: function (danePracownika) {
$("#Id_department")
.dxTextBox("instance")
.option("value", danePracownika.UserDepartament);
$("#Id_manager")
.dxTextBox("instance")
.option("value", danePracownika.UserManager);
alert(danePracownika.UserDepartament + " " + danePracownika.UserManager);
},
failure: function (error) {
alert(error);
},
error: function (error) {
alert(error);
}
});
}
</script>
Controller:
[HttpPost]
public ActionResult GetDepartmentAndManager(string userId)
{
dynamic serializer = JsonConvert.DeserializeObject<IDictionary>(userId);
var IdCzlowieka = serializer["nazwaValueId"];
int IntIdCzlowieka = Convert.ToInt32(IdCzlowieka);
var danePracownika = _uzytkownicyContext.Uzytkownicy.Where(x => x.Id == IntIdCzlowieka).Select(s => new
{
UserDepartament = s.Departament,
UserManager = s.ManagerLogin
});
return Json(danePracownika);
}
return : //
[0] { UserDepartament = "there is value here / string", UserManager = "there is value here / string" }
EDIT
The question is, what's wrong with the code, why it doesn't work for me?
.
I see that in Your GetDepartmentAndManager You are not using Your passed parameter userID:
var danePracownika = ... .Where(x => x.Id == IntIdCzlowieka)...
should be Where(x => x.Id == userId) instead.
The next thing that came to me is the value You are acctualy getting inside the controller action; based on the JS code I would say that this is not the ID of the employee what You are passing but the stringified object { "nazwaValueId": ... } that in the best case would be handled by the server and You will get the raw string as a value of userId (unless You have defined a IModelBinder class that would handle conversion from stringified { "nazwaValueId": ... } to the value of that field - more on that You can find here).
Oh any by the way - please try to avoid mixing languages. I have a friend in the company which was forced to work with the german project and all their code was written in German - You would DEFINETLY won't be happy working with it. But if this a project made only by PL for PL, that is some kind of acceptable approach I assume.
Also I highly advice You to not use HTTP POST method for getting data. To make long story short there is a convention that GET requests are for getting the data and You can call it as many times You like without affecting the state (było takie mądre słowo na to, ale nie pamiętam ;)) and POST is for saving/modifing data and should always redirect to GET method on return. You can read more about it here.
EDIT:
Ok, for some reason I have found that the call in the current form is sending data not as a body but as a form. I don't know, I don't use jQuery. But here is the reqest:
so I changed the signature of the action to
public ActionResult GetDepartmentAndManager([FromForm]string userId)
to get is started working. Maybe on Your side it is just working fine, I don't know. But what I have found is that while sending the responce to the client we end up with... this:
so as You can see either Ajax or server changed the JSON keys to be kebabCase not PascalCase and that's why You are getting undefined values. Because properties You arereading do not exists. Just check it out: alert(danePracownika.userDepartament + " " + danePracownika.userManager);
UPDATE:
I checked it, it was not server's fault:
I have a Kendo Grid on the start page of a .NET Core 2.0 MVC web app. The data source is populated via ViewData on page load:
public IActionResult Index()
{
var allForms = formsDB.FormHeader.Select(x => x);
ViewData["AllForms"] = allForms;
<...>
return View();
}
The data source object (FormHeader) contains a column with an employee code. One of the columns in my Kendo grid is currently displaying the employee code, but I'd like to display the full name via .ClientTemplate:
#(Html.Kendo().Grid<Forms.Models.FormHeader>()
.Name("HeadersMasterGrid")
.BindTo((IQueryable<Forms.Models.FormHeader>)ViewData["AllForms"])
.Pageable()
.Columns(columns =>
{
columns.Bound(p => p.EmployeeCode).Title("Employee")
/*.ClientTemplate("#=getEmployeeName(EmployeeCode)#")*/;
<..>
I'd like to display the employee's first and last name instead of the code. I set up an IAction result in my Form Controller to receive an employee code and return the full name (via ~/Form/GetEmployee/):
public ActionResult GetEmployee(string id)
{
var employee = theDB.EmployeeMasters.FirstOrDefault(x => x.EmployeeCode.Trim() == id.ToUpper());
BasicEmployee basicEmployee = new BasicEmployee(employee.FirstName, employee.LastName, id.Trim());
//return Json(basicEmployee);
return Json(basicEmployee.FullName);
}
Lastly, I added some jQuery script to my view that I was hoping would open the URL, retrieve the full name, and return that into the .ClientTemplate of the Kendo Grid column. You can see that I have tried returning just the full name, but also returning the entire object and then parsing/returning the full name from the object.
The second function in the block below was my most recent attempt after receiving some instruction about promises/callbacks (which are still pretty fuzzy).
#*function getEmployeeName(empCode) {
$.getJSON('#Url.Action("GetEmployee", "Form")' + "/" + empCode,
function(data) {
//var response = $.parseJSON(data);
//return response.FullName.toString();
return $.parseJSON(data);
}, 'json');
}*#
function getEmployeeName(empCode) {
var promise = $.getJSON('#Url.Action("GetEmployee", "Form")' + "/" + empCode);
$.when(promise).done(function(data) {
return JSON.stringify(data);
});
}
I've spent quite a bit of time with the Kendo docs, Google, and two Slack workspaces for developers, but I'm not finding anything that works. I have no experience with either Javascript or jQuery before this project and am still very much in the learning phase. I understand that I am most likely going about this incorrectly (or missing an easy solution), but I'd like to know how I can accomplish this.
i am creating a web app with the help of angularjs,
on one of my button click i am calling a web service through angularjs
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public void getuprec(string id)
{
List<object> selectrecd = new List<object>();
SqlCommand cmd = new SqlCommand("select * from erp_admin.CompanySonVinUnitVenueRpt where comsonvinid in (select id from companysonvinunitvenue where id='"+id+"')",con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while(dr.Read())
{
selectrecd.Add(new
{
attendee1 = dr["comattendee1"].ToString(),
attendee2 = dr["comattendee2"].ToString(),
totalmale = dr["attendeetotalmale"].ToString(),
totalfemale = dr["attendeetotalfemale"].ToString(),
unit1 = dr["unitattendee1"].ToString(),
unitd1 = dr["unitattendee1desig"].ToString(),
unit2 = dr["unitattendee2"].ToString(),
unitd2 = dr["unitattendee2desig"].ToString(),
unit3 = dr["unitattendee3"].ToString(),
unitd3 = dr["unitattendee3desig"].ToString(),
unit4 = dr["unitattendee4"].ToString(),
unitd4 = dr["unitattendee4desig"].ToString(),
unit5 = dr["unitattendee5"].ToString(),
unitd5 = dr["unitattendee5desig"].ToString(),
remarks = dr["remarks"].ToString()
});
}
con.Close();
var json = js.Serialize(selectrecd);
Context.Response.Write("{" + '"' + "selectrecd" + '"' + ":" + json + "}");
}
this is my webservice which is working fine (i tested) and my angularjs file
$scope.updatefunction = function (param) {
$http.get('/frmattendencerptqed.asmx/getuprec', {
params: {
id: $scope.updateparam.comsonvinid
}
})
.then()
{
}
}
this is my angularjs
this is my input field
<input type="text" ng-model="remarks" style="width:100%;" />
now i need to take the previous value from my database and bind the value on my textbox, and if user edit the textbox then the value must be updated on button click
how i need to do this
this is my input field
<input type="text" ng-model="remarks" style="width:100%;" />
now i need to take the previous value from my database and bind the
value on my textbox, and if user edit the textbox then the value must
be updated on button click
Which one remarks property ?
In your webservice you returns a json object which contains a array of structured objects which each one may contain a remark property.
Can you post the resulted json of webservice call in order to give us more details ?
About how to retrieve and bind the data in your angular js controller, here is my answer.
From https://docs.angularjs.org/api/ng/service/$http
you can retrieve response from data property in returned object.
data – {string|Object} – The response body transformed with the
transform functions.
So you can do something like that:
$scope.updatefunction = function (param) {
$http.get('/frmattendencerptqed.asmx/getuprec', {
params: {
id: $scope.updateparam.comsonvinid
}
})
.then(
// handling if ok
function(response){
$scope.remarks=response.data.selectrecd[indexYourWish].remarks
},
function(errResponse){
// handling if error
return $q.reject(errResponse);
}
);
}
As explains previously, I refer to an array to retrieve the information in response.data with an index you should define or not use at all index if you don't return a array.
remarks should be a variable in the scope of your controller.
The more relevant syntax to use for controller depends on how you declare things in Angular (Personally, I avoid $scope.xxx syntax).
Post more of your JS code if you want a more precise answer.
It's just how angularjs normally works, the two way databinding follow this tutorial:
http://www.w3schools.com/angular/angular_databinding.asp
you'll see that what you only need is to call the update function from your controller and pass it the variable you bind to the input.
Of course this variable assigned to $scope or to this in the controller (there are two ways).
I am working on a project where the client wants to be able to have a "Control" on the page where the user can start typing and a data grid will filter with each keystroke.
The filter should use the starts with operator, and removing all of the characters inside of the input ("control") will reset the Grid to its original unfiltered state.
My Controller, I don't want to modify it or add additional parameters:
public JsonResult GetFoo([DataSourceRequest]DataSourceRequest request, bool active = true)
{
List<Foo> model = FooContext.Foo.GetFoo(active);
model = model.OrderBy(m => m.Name).ToList();
return Json(model.ToDataSourceResult(request),JsonRequestBehavior.AllowGet);
}
This is my current Gird:
#(Html.Kendo().Grid<foo>()
.Name("fooTable")
.PrefixUrlParameters(Settings.Grid.PrefixUrlParameters)
.Columns(columns =>
{
columns
.Bound("fooName")
.ClientTemplate("<a href='#= Id #'>#= fooName #</a>");
columns
.Bound("StateName")
.Title("State").Width(120);
columns.Bound("PreviousYearsHomes")
.Title("Previous Years Homes")
.Width(120);
columns.Bound("CurrentYearsHomes")
.Title("Current Years Homes")
.Width(120);
.Sortable()
.Resizable(q => q.Columns(true))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("GetBuilders", "Builders", new { Area = "Administrator", active = true }))
)
)
The Filter should filter the 'fooName' column.
I would recommend specifying the .Data(string handler) method available on the data source, for example
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read
.Action("GetBuilders", "Builders", new { Area = "Administrator", active = true })
.Data("getDataParams")
)
)
This allows you to specify a javascript function that returns a JSON object defining additional parameters to append to the ajax request.
You can use something like this:
var getDataParams = function (e) {
var result = {
name: $('#fooNameInput').val()
}
return result;
};
And to trigger a refresh of the grid (from a key up event or similar):
$("#fooTable").data("kendoGrid").dataSource.read();
Some docs to assist:
Kendo Forums working example
MVC Fluent docs
I really didn't want to answer my own question, but for anyone trying this for themselves this is what I did to get the results I was looking for.
Added an input with an Id of fooNameInput
<script type="text/javascript">
$(function () {
$('#fooNameInput').on("keyup change", function () {
var Value = $(this).val();
if (Value.length) {
FilterGridByName(Value, 'Name');
}
else {
$('#fooTable').data("kendoGrid").dataSource.filter([]);
}
});
function FilterGridByName(Value, Field) {
if (Field != "") {
if (Value != "") {
$('#fooTable').data("kendoGrid").dataSource.filter({ field: Field, operator: "startswith", value: Value })
}
else {
$('#fooTable').data("kendoGrid").dataSource.filter([]);
}
}
}
});
</script>
This is working as I wanted it to work but if there is a better way please let me know in the comments and I will update this answer/remove it.
This is a another option that I feel is important to include -
Another Option Provided by : https://stackoverflow.com/users/2293059/stevechapman
I would recommend specifying the .Data(string handler) method available on the data source, for example
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read
.Action("GetBuilders", "Builders", new { Area = "Administrator", active = true })
.Data("getDataParams")
)
)
This allows you to specify a javascript function that returns a JSON object defining additional parameters to append to the ajax request.
You can use something like this:
var getDataParams = function (e) {
var result = {
name: $('#fooNameInput').val()
}
return result;
};
And to trigger a refresh of the grid (from a key up event or similar):
$("#fooTable").data("kendoGrid").dataSource.read();
Some docs to assist:
Kendo Forums working example
MVC Fluent docs
I'm trying to convert my basic crud operations into an API that multiple components of my application can use.
I have successfully converted all methods, except the update one because it calls for each property on the object to be declared before the put request can be executed.
controller
$scope.update = function(testimonial, id) {
var data = {
name: testimonial.name,
message: testimonial.message
};
dataService.update(uri, data, $scope.id).then(function(response) {
console.log('Successfully updated!');
},
function(error) {
console.log('Error updating.');
});
}
dataService
dataService.update = function(uri, data, id) {
var rest = Restangular.one(uri, id);
angular.forEach(data, function(value, key) {
// needs to be in the format below
// rest.key = data.key
});
// needs to output something like this, depending on what the data is passed
// rest.name = data.name;
// rest.message = data.message;
return rest.put();
}
I tried to describe the problem in the codes comments, but to reiterate I cannot figure out how to generate something like rest.name = data.name; without specifying the name property because the update function shouldn't need to know the object properties.
Here is what the update method looked like before I started trying to make it usable by any of my components (this works)
Testimonial.update = function(testimonial, id) {
var rest = Restangular.one('testimonials', id);
rest.name = testimonial.name;
rest.message = testimonial.message;
return rest.put();
}
How can I recreate this without any specific properties parameters hard-coded in?
Also, my project has included lo-dash, if that helps, I don't know where to start with this problem. Thanks a ton for any advice!
Try like
angular.extend(rest,testimonial)
https://docs.angularjs.org/api/ng/function/angular.extend