How to get attributes from OData response via AJAX? - ajax

I'm working on the MVC application which using OData & Web API via ajax. I'm trying to do paging from server side by using OData filter attributes. Here is my code of Controller.
[RoutePrefix("OData/Products")]
public class ProductsController : ODataController
{
private List<Product> products = new List<Product>
{
new Product() { Id = 1, Name = "Thermo King MP-3000", Price = 300, Category = "Thermo King" },
new Product() { Id = 2, Name = "Thermo King MP-4000", Price = 500, Category = "Thermo King" },
new Product() { Id = 3, Name = "Daikin Decos III c", Price = 200, Category = "Daikin" },
new Product() { Id = 4, Name = "Daikin Decos III d", Price = 400, Category = "Daikin" },
new Product() { Id = 5, Name = "Starcool RCC5", Price = 600, Category = "Starcool" },
new Product() { Id = 6, Name = "Starcool SCC5", Price = 700, Category = "Starcool" }
};
[EnableQuery(PageSize=2)]
public IQueryable<Product> Get()
{
return products.AsQueryable<Product>();
}
//[EnableQuery]
//public SingleResult<Product> Get([FromODataUri] int id)
//{
// var result = products.Where(x => x.Id.Equals(id)).AsQueryable();
// return SingleResult.Create<Product>(result);
//}
[EnableQuery]
public Product Get([FromODataUri] int id)
{
return products.First(x => x.Id.Equals(id));
}
}
And here is my code of javascript:
<script type="text/javascript">
$(document).ready(function () {
var apiUrl = "http://localhost:56963/OData/Products";
$.getJSON(apiUrl,
function (data) {
$("#div_content").html(window.JSON.stringify(data));
}
);
//$.get(apiUrl,
//function (data) {
// alert(data[0]);
// $("#div_content").html(data);
//});
});
</script>
The response from OData is JSON result like:
{"#odata.context":"http://localhost:56963/OData/$metadata#Products","value":[{"Id":1,"Name":"Thermo King MP-3000","Price":300,"Category":"Thermo King"},{"Id":2,"Name":"Thermo King MP-4000","Price":500,"Category":"Thermo King"}],"#odata.nextLink":"http://localhost:56963/OData/Products?$skip=2"}
I was trying to get "#odata.nextLink" but failed, there is no way to get "odata.nextLink" by "data.#odata.nextLink" from javascript.
Any one can help me to get through this?

After parse the string to json, data['#odata.nextLink'] can work:
var data = '{"#odata.context":"http://localhost:56963/OData/$metadata#Products","value":[{"Id":1,"Name":"Thermo King MP-3000","Price":300,"Category":"Thermo King"},{"Id":2,"Name":"Thermo King MP-4000","Price":500,"Category":"Thermo King"}],"#odata.nextLink":"http://localhost:56963/OData/Products?$skip=2"}';
data = JSON.parse(data);
alert(data['#odata.nextLink']);

Related

NEST (ElasticSearch) search response drops aggregates

Here is a query that works in ElasticSearch.
"query":{
"match_all":{
}
},
"size":20,
"aggs":{
"CompanyName.raw":{
"terms":{
"field":"CompanyName.raw",
"size":20,
"order":{
"_count":"desc"
}
}
}
}
}
The response from ElasticSearch has a property aggregations['CompanyName.raw']['buckets'] which is an array.
I use this code to exeute the same query via NEST
string responseJson = null;
ISearchResponse<ProductPurchasing> r = Client.Search<ProductPurchasing>(rq);
using (MemoryStream ms = new MemoryStream())
{
Client.RequestResponseSerializer.Serialize<ISearchResponse<ProductPurchasing>>(r, ms);
ms.Position = 0;
using (StreamReader sr = new StreamReader(ms))
{
responseJson = sr.ReadToEnd();
}
}
However, in the resulting responseJson this array is always empty.
Where hs it gone?
How can I get it back?
Or is it that NEST doesn't support aggregates?
NEST does support aggregation, you can have a look into docs on how to handle aggregation response with NEST help.
Here you can find a short example of writing and retrieving data from simple terms aggregation:
class Program
{
public class Document
{
public int Id { get; set; }
public string Name { get; set; }
public string Brand { get; set; }
public string Category { get; set; }
public override string ToString() => $"Id: {Id} Name: {Name} Brand: {Brand} Category: {Category}";
}
static async Task Main(string[] args)
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings = new ConnectionSettings(pool);
connectionSettings.DefaultIndex("documents");
var client = new ElasticClient(connectionSettings);
var deleteIndexResponse = await client.Indices.DeleteAsync("documents");
var createIndexResponse = await client.Indices.CreateAsync("documents", d => d
.Map(m => m.AutoMap<Document>()));
var indexDocument = await client
.IndexDocumentAsync(new Document {Id = 1, Brand = "Tommy", Category = "men"});
var indexDocument2 = await client
.IndexDocumentAsync(new Document {Id = 2, Brand = "Diesel", Category = "men"});
var indexDocument3 = await client
.IndexDocumentAsync(new Document {Id = 3, Brand = "Boss", Category = "men"});
var refreshAsync = client.Indices.RefreshAsync();
var searchResponse = await client.SearchAsync<Document>(s => s
.Query(q => q.MatchAll())
.Aggregations(a => a
.Terms("brand", t => t
.Field(f => f.Brand.Suffix("keyword")))));
var brands = searchResponse.Aggregations.Terms("brand");
foreach (var bucket in brands.Buckets)
{
Console.WriteLine(bucket.Key);
}
}
}
Prints:
Boss
Diesel
Tommy
Hope that helps.

ASP.NET MVC passing data to partial view through ajax

I am using full calendar library, where I load my events as JSON and display them in the calendar.
What I would like to do next is to load an id of the latest event and display information about the event from the model in the partial view. This is my code so far:
<div id="calendar"></div>
<div id="myPartial"></div>
<script>
$('#calendar').fullCalendar({
aspectRatio: 3,
events: function (start, end, timezone, callback) {
$.getJSON("#Url.Action("GetEvents")", function (locationsArray) {
var result = $(locationsArray).map(function () {
return {
id: this.idEvent,
title: this.eventName,
start: this.startTime,
end: this.endTime,
allDay: this.allDay
};
}).toArray();
callback(result);
var id_latest = result[result.length - 1].id
success: $(function (id_latest) {
$.ajax({
type: "POST",
url: '#Url.Action("AddContent","Home")',
data: { id: id_latest },
error: function () {
alert("An error occurred.");
},
success: function (data) {
$("#myPartial").html(data);
}
});
});
});
}
});
</script>
What am I missing here? What is the proper way to do it?
Edit:
Controller:
namespace bezeckaApp.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
public ActionResult AddContent(int? id)
{
return PartialView("~/Views/Home/AddContent.cshtml");
}
public ActionResult GetEvents()
{
List<Treninky> trenink = new List<Treninky>();
trenink.Add(new Treninky() { idEvent = 1, eventName = "Morning run", startTime = "2017-07-01T08:00:00Z", endTime = "2017-07-01T09:00:00", allDay = false });
trenink.Add(new Treninky() { idEvent = 2, eventName = "Evening run", startTime = "2017-07-05T17:00:00Z", endTime = "2017-07-05T18:00:00", allDay = false });
trenink.Add(new Treninky() { idEvent = 3, eventName = "Evening run", startTime = "2017-07-08T17:00:00Z", endTime = "2017-07-08T18:00:00", allDay = false });
return Json(trenink, JsonRequestBehavior.AllowGet);
}
}
}
Model:
namespace bezeckaApp.Models
{
public class Treninky
{
public int idEvent { set; get; }
public string eventName { set; get; }
public string startTime { set; get; }
public string endTime { set; get; }
public bool allDay { set; get; }
}
}
EDIT
this still causes id in AddContent method NULL
public ActionResult AddContent(int? id)
{
List<Treninky> trenink = new List<Treninky>();
trenink.Add(new Treninky() { idEvent = 1, eventName = "Morning run", startTime = "2017-07-01T08:00:00Z", endTime = "2017-07-01T09:00:00", allDay = false });
trenink.Add(new Treninky() { idEvent = 2, eventName = "Evening run", startTime = "2017-07-05T17:00:00Z", endTime = "2017-07-05T18:00:00", allDay = false });
trenink.Add(new Treninky() { idEvent = 3, eventName = "Evening run", startTime = "2017-07-08T17:00:00Z", endTime = "2017-07-08T18:00:00", allDay = false });
return PartialView("~/Views/Home/AddContent.cshtml",trenink.Find(id));
}
If yours javascript is working, and you getting latest ID then it should work.

How to working with data from client side using Observables

I am using the Grid of Kendo (Angular 2) for Add/Edit/Delete a Row in the grid:
http://www.telerik.com/kendo-angular-ui/components/grid/editing/
In the original Code, the data is obtained from a rest service like this:
private fetch(action: string = "", data?: Product): Observable<Product[]> {
return this.jsonp
.get(`http://demos.telerik.com/kendo-ui/service/Products/${action}? callback=JSONP_CALLBACK${this.serializeModels(data)}`)
.map(response => response.json());
}
But, I want to work with a array for add/edit/delete rows in memory. Next, I want to do click in the button submit and send the data (with all my changes) to the server.
My solution for this is like this:
https://gist.github.com/joedayz/9e318a47d06a7a8c2170017eb133a87e
Overview:
I declare an array:
private view: Array = [{ProductID: 1, ProductName: "pelotas", Discontinued: undefined, UnitsInStock: 80}];
and override the fetch method like this:
private fetch(action: string = "", data?: Product): Observable<Product[]> {
/*return this.jsonp
.get(`http://demos.telerik.com/kendo-ui/service/Products/${action}?callback=JSONP_CALLBACK${this.serializeModels(data)}`)
.map(response => response.json());*/
debugger;
if(action=="create"){
var product : Product = new Product(-1, data.ProductName, data.Discontinued, data.UnitsInStock);
this.view.push(product);
}else if(action=="update"){
var indice = this.view.indexOf(data);
if(indice>=0)
this.view[indice] = (JSON.parse(JSON.stringify(data)));
}else if(action=="destroy"){
var indice = this.view.indexOf(data);
if(indice>=0)
this.view.splice(indice, 1);
}
return Observable.of(this.view);
}
My Question is: Exists some way of communicate the create/update/delete of items in my array of a simple or reactive form to my grid?
As you are using in-memory array you do not need to use Observables. The Grid component is already bound to the array, thus it is just necessary to manipulate the data. For example:
export class AppComponent {
public dataItem: Product;
#ViewChild(GridEditFormComponent) protected editFormComponent: GridEditFormComponent;
private view: Array<Product> = [{ ProductID: 1, ProductName: "pelotas", Discontinued: undefined, UnitsInStock: 80 }];
public onEdit(dataItem: any): void {
this.dataItem = Object.assign({}, dataItem);
}
public onCancel(): void {
this.dataItem = undefined;
}
public addProduct(): void {
this.editFormComponent.addProduct();
}
public onSave(product: Product): void {
if (product.ProductID === undefined) {
this.createProduct(product);
} else {
this.saveProducts(product);
}
}
public onDelete(e: Product): void {
this.deleteProduct(e);
}
public saveProducts(data: Product): void {
var index = this.view.findIndex(x => x.ProductID === data.ProductID);
if (index !== -1) {
this.view = [
...this.view.slice(0, index),
data,
...this.view.slice(index + 1)
];
}
}
public createProduct(data: Product): void {
this.view = [...this.view, data];
}
public deleteProduct(data: Product): void {
this.view = this.view.filter(x => x.ProductID !== data.ProductID);
}
}

$select on navigation property / WebApi 2.0 / OData 4

Given the following simple OData 4 controller (please see below), how do I $select just the cities?
http://localhost//api/Customers?$select=Location
Gives me:
{
"#odata.context":"http://localhost/api/$metadata#Customers(Location)","value":[
{
"Location":{
"Country":"Ireland","City":"Sligo"
}
},{
"Location":{
"Country":"Finland","City":"Helsinki"
}
}
]
}
But I don't know how to drill down one deeper so that I just get the cities. Is this even possible?
public class CustomersController : ODataController
{
private List<Customer> customers = new List<Customer>()
{
new Customer
{
CustomerId = 1,
Location = new Address
{
City = "Sligo",
Country = "Ireland"
}
},
new Customer
{
CustomerId = 2,
Location = new Address
{
City = "Helsinki",
Country = "Finland"
}
}
};
[EnableQuery]
public List<Customer> Get()
{
return customers;
}
}
The grammar for $select does not allow a path expression like Location/City. Your best bet is to define an OData function bound to the Customers entity set. E.g.,
[HttpGet]
public IEnumerable<string> GetCities()
{
return customers.Select(c => c.Location.City);
}
And invoke it as follows:
GET http://localhost/api/Customers/ServiceNamespace.GetCities

ASP.NET MVC 3 WebGrid, preserve the paging and define the route

I am start to learn the MVC3, But i have some problem on WebGrid,
The Controller name is TestController, so i navigate to :
http://localhost:53503/Test/
And the Webgrid shown as below:
two column : ID and Name.
the 3rd & 4th column : Actionlink and item.GetSelectLink.
The first problem is :
Assume i viewing page 3 of webgrid, and press the ActionLink,after go-thought the TestContoller's Action, the webgrid will return to page 1 after PostBack.
However,if i press the [View(GetSelectLink)] on right end:
(e.g. http://localhost:53503/Test/?gridItems_page=3&gridItems_selectedRow=3
It works.
So, i should use ActionLink or GetSelectLink for general Add/Update/Delete operation?
MVC3 hasn't viewstate / control state, so how can i preserve the current page selection after PostBack?
The second problem is :
The (href) of ActionLink is :
http://localhost:53503/Test/GetSelection/7?Name=PSP
I would make it to
http://localhost:53503/Test/GetSelection/7/PSP
I add a new route to global.asax, but it is no luck.
Thanks you very much for help.
It is my code:
Views/Test/Index.cshtml
#model List<MvcContract.Controllers.Products>
#{
System.Web.Helpers.WebGrid grid = new System.Web.Helpers.WebGrid(
source: Model,
canPage: true,
rowsPerPage: 3,
fieldNamePrefix: "gridItems_",
pageFieldName: "page",
selectionFieldName: "selectedRow"
);
}
#{
if (Model != null)
{
#grid.GetHtml(
columns: grid.Columns(
grid.Column("ID"),
grid.Column("Name"),
grid.Column(format: (item) => Html.ActionLink("View(ActionLink)", "GetSelection", new { ID = item.ID, Name = item.Name })),
grid.Column(format: (item) => item.GetSelectLink("View(GetSelectLink)"))
)
);
}
}
Controllers/TestController.cs
namespace MvcContract.Controllers
{
public class Products
{
public string ID { get; set; }
public string Name { get; set; }
public List<Products> GetItems()
{
List<Products> items = new List<Products>();
items.Add(new Products() { ID = "1", Name = "PS3" });
items.Add(new Products() { ID = "2", Name = "XBox360" });
items.Add(new Products() { ID = "3", Name = "Wii" });
items.Add(new Products() { ID = "4", Name = "Saturn" });
items.Add(new Products() { ID = "5", Name = "Dreamcast" });
items.Add(new Products() { ID = "6", Name = "NDS" });
items.Add(new Products() { ID = "7", Name = "PSP" });
items.Add(new Products() { ID = "8", Name = "NeoGeo" });
items.Add(new Products() { ID = "9", Name = "3DO" });
items.Add(new Products() { ID = "10", Name = "Playdia" });
return items;
}
}
public class TestController : Controller
{
//Bind data to WebGrid
public ActionResult Index()
{
Products products = new Products();
return View(products.GetItems());
}
//Some Logic
public ActionResult GetSelection(string ID, string Name)
{
string SelectedID = ID;
return RedirectToAction("Index");
}
}
}
RegisterRoutes() in Global.asax.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Test_GetSelection", // Route name
"{controller}/{action}/{id}/{name}", // URL with parameters
new { controller = "Test", action = "GetSelection", id = UrlParameter.Optional, name = UrlParameter.Optional } // Parameter defaults
);
}
Check out this discussion. I think one of several solutions there may solve your issue.
Since its been a whole year since you posted this, please post an answer if you figured it out another way.

Resources