SAPUI OData 405 (Method Not Allowed) - odata

I am new to SAPUI and I'm doing some tests with OData. I built a simple project showing products of an oData service and a buttons for create/delete/edit a product.
When I try to create a new product or to delete/update it I got:
POST MyUri.../OData/OData.svc 405 (Method Not Allowed).
This is my browser console:
My files:
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8' />
<script src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m, sap.ui.commons, sap.ui.table"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-theme="sap_bluecrystal">
</script>
<!-- only load the mobile lib "sap.m" and the "sap_bluecrystal" theme -->
<script>
var oModel = new sap.ui.model.odata.ODataModel("https://cors-anywhere.herokuapp.com/http://services.odata.org/V2/OData/OData.svc/");
/* var oModel = new sap.ui.model.odata.ODataModel("https://services.odata.org/OData/OData.svc/"); */
/* var oModel = new sap.ui.model.odata.v4.ODataModel("http://localhost:8080/odata/DemoService.svc/"); */
sap.ui.getCore().setModel(oModel);
var aColumn1 = [
new sap.m.Column({
header: new sap.m.Label({
text: "ID"
})
}),
new sap.m.Column({
header: new sap.m.Label({
text: "Name"
})
}),
new sap.m.Column({
header: new sap.m.Label({
text: "Description"
})
}),
new sap.m.Column({
header: new sap.m.Label({
text: "Release Date"
})
}),
new sap.m.Column({
header: new sap.m.Label({
text: "Rating"
})
}),
new sap.m.Column({
header: new sap.m.Label({
text: "Price"
})
}),
new sap.m.Column({
header: new sap.m.Label({
text: "Supplier"
})
})
];
var oTemplate1 = new sap.m.ColumnListItem({
cells: [
new sap.m.Text({
text: "{ID}"
}),
new sap.m.Text({
text: "{Name}"
}),
new sap.m.Text({
text: "{Description}"
}),
new sap.m.Text({
text: "{ReleaseDate}"
}),
new sap.m.Text({
text: "{Rating}"
}),
new sap.m.Text({
text: "{Price}"
}),
new sap.m.Text({
text: "{Supplier/Name}"
}),
]
});
var oTable1 = new sap.m.Table({
id: "table",
columns: aColumn1
});
oTable1.bindItems({
path: '/Products',
parameters:{expand : 'Supplier'},
template:oTemplate1
});
console.log(oTable1);
var page = new sap.m.Page({
id: "page",
title: "OData Web App",
showNavButton: false,
content: [oTable1]
});
var app = new sap.m.App();
app.addPage(page);
app.placeAt("content");
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
</body>
</html>
Product.controller.js (I tried different uri)
sap.ui.controller("products.Product", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* #memberOf products.Product
*/
onInit: function() {
// var oModel = new sap.ui.model.odata.ODataModel("proxy/https/services.odata.org/V3/OData/OData.svc");
// var oModel = new sap.ui.model.odata.ODataModel("proxy/https/services.odata.org/V3/(S(k42qhed3hw4zgjxfnhivnmes))/OData/OData.svc");
// var oModel = new sap.ui.model.odata.ODataModel("proxy/https/services.odata.org/V3/(S(blacksheep))/OData/OData.svc");
// var oModel = new sap.ui.model.odata.ODataModel("proxy/http/services.odata.org/V3/(S(au3m0bej1w40a00fq1tpt540))/OData/OData.svc");
// var oModel = new sap.ui.model.odata.ODataModel("proxy/https/services.odata.org/V3/(S(3ngooq0fkelm0nublhbj01xu))/OData/OData.svc");
var oModel = new sap.ui.model.odata.ODataModel("proxy/https/services.odata.org/V3/(S(gvhowm5dxqs50fz45zzouph3))/OData/OData.svc");
oModel.oHeaders = {
"DataServiceVersion": "3.0",
"MaxDataServiceVersion": "3.0"
};
// this.getView().setModel(oModel, "products");
sap.ui.getCore().setModel(oModel,"products");
// console.log(oModel);
},
/**
* Similar to onAfterRendering, but this hook is invoked before the controller's View is re-rendered
* (NOT before the first rendering! onInit() is used for that one!).
* #memberOf products.Product
*/
// onBeforeRendering: function() {
//
// },
/**
* Called when the View has been rendered (so its HTML is part of the document). Post-rendering manipulations of the HTML could be done here.
* This hook is the same one that SAPUI5 controls get after being rendered.
* #memberOf products.Product
*/
onAfterRendering: function() {
$("#formId").hide();
},
/**
* Called when the Controller is destroyed. Use this one to free resources and finalize activities.
* #memberOf products.Product
*/
// onExit: function() {
//
// }
mode: 0,
resetForm: function(){
$("#name").val('');
$("#description").val('');
$("#price").val('');
$("#rating").val('');
$("#id").val('');
},
create: function(){
this.mode = 'create';
this.resetForm();
$("#formId").slideDown(300, function() {
// var id = sap.ui.getCore().byId('tableId')._getRowCount();
// $("#id").val(id);
});
},
edit: function(){
this.mode = 'edit';
var oTable = sap.ui.getCore().byId('tableId');
var selected = oTable.getSelectedIndex();
// alert(selected);
if(selected ==-1){
alert("Select row");
}else{
$("#formId").slideDown(function(){
var data = oTable.getModel('products').oData['Products('+ selected +')'];
var id = data.ID;
var description = data.Description;
var price = data.Price;
var rating = data.Rating;
var name = data.Name;
$("#name").val(name);
$("#description").val(description);
$("#price").val(price);
$("#rating").val(rating);
$("#id").val(id);
})
}
},
removeId: 0,
remove: function(){
this.mode = 'delete';
var oTable = sap.ui.getCore().byId('tableId');
var selected = oTable.getSelectedIndex();
if(selected ==-1){
alert("Select row");
}else{
var data = oTable.getModel('products').oData['Products('+ selected +')'];
this.removeId = data.ID;
this.save();
}
},
save: function(){
var requestObj = {
requestUri: '',
method: '',
headers: {
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/json;odata=minimalmetadata",
"DataServiceVersion": "3.0",
"MaxDataServiceVersion": "3.0",
"Accept": "application/json;odata=minimalmetadata"
}
};
var newData={
"odata.type": "ODataDemo.Product",
"ID": $("#id").val(),
"Name": $("#name").val(),
"Description": $("#description").val(),
"ReleaseDate": $("#date").val(),
// "DiscontinuedDate": null
"Rating": $("#rating").val(),
"Price": $("#price").val(),
}
if(this.mode == 'create'){
// var url = "proxy/https/services.odata.org/V3/(S(3ngooq0fkelm0nublhbj01xu))/OData/OData.svc";
var url = "proxy/https/services.odata.org/V3/(S(gvhowm5dxqs50fz45zzouph3))/OData/OData.svc";
var method = "POST";
requestObj.requestUri = url;
requestObj.method = method;
requestObj.data = newData;
}else if(this.mode == 'edit'){
var id = $("#id").val();
// var url = "proxy/https/services.odata.org/V3/(S(3ngooq0fkelm0nublhbj01xu))/OData/OData.svc";
var url = "proxy/https/services.odata.org/V3/(S(gvhowm5dxqs50fz45zzouph3))/OData/OData.svc";
var method = "PUT";
requestObj.requestUri = url;
requestObj.method = method;
requestObj.data = newData;
}else if(this.mode == 'delete'){
var id = this.removeId;
var url = "proxy/https/services.odata.org/V3/(S(gvhowm5dxqs50fz45zzouph3))/OData/OData.svc";
var method = "DELETE";
requestObj.requestUri = url;
requestObj.method = method;
}
OData.request(requestObj, function() {
sap.ui.getCore().getModel('products').refresh();
$("#formId").slideUp();
});
}
});
Product.view.js
sap.ui.jsview("products.Product", {
/** Specifies the Controller belonging to this View.
* In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.
* #memberOf products.Product
*/
getControllerName : function() {
return "products.Product";
},
/** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed.
* Since the Controller is given to this method, its event handlers can be attached right away.
* #memberOf products.Product
*/
createContent : function(oController) {
var oMatrix = new sap.ui.commons.layout.MatrixLayout({
layoutFixed: true,
width: '300px',
columns: 3
});
oMatrix.createRow(
new sap.ui.commons.Button({
text: "Create",
width: '100px',
press: function(){
oController.create();
}
}),
new sap.ui.commons.Button({
text: "Edit",
width: '100px',
press: function(){
oController.edit();
}
}),
new sap.ui.commons.Button({
text: "Delete",
width: '100px',
press: function(){
oController.remove();
}
})
);
var oLayout = new sap.ui.layout.form.SimpleForm("formId",{
title: "Product Detail",
content: [
new sap.ui.commons.Label({text: "ID"}),
// new sap.ui.commons.TextField("id",{width: '200px', editable: false}),
new sap.ui.commons.TextField("id",{width: '200px'}),
new sap.ui.commons.Label({text: "Name"}),
new sap.ui.commons.TextField("name",{width: '200px'}),
new sap.ui.commons.Label({text: "Description"}),
new sap.ui.commons.TextField("description",{width: '200px'}),
new sap.ui.commons.Label({text: "Price"}),
new sap.ui.commons.TextField("price",{width: '200px'}),
new sap.ui.commons.Label({text: "Rating"}),
new sap.ui.commons.TextField("rating",{width: '200px'}),
new sap.ui.commons.Label({text: "ReleaseDate"}),
new sap.ui.commons.TextField("date",{width: '200px', value:"2019-09-19T22:00:00"}),
new sap.ui.commons.Label({text: ""}),
new sap.ui.commons.Button({
text: "Save",
width: '100px',
press: function(){
oController.save()
}
})
]
});
//TABLE
var oTable = new sap.ui.table.Table("tableId",{
visibleRowCount: 8,
editable: false
});
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "ID"}),
visible: true,
template: new sap.ui.commons.TextView({text: "{products>ID}"})
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Name"}),
visible: true,
template: new sap.ui.commons.TextView({text: "{products>Name}"})
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Description"}),
visible: true,
template: new sap.ui.commons.TextView({text: "{products>Description}"})
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Price"}),
visible: true,
template: new sap.ui.commons.TextView({text: "{products>Price}"})
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Rating"}),
visible: true,
template: new sap.ui.commons.TextView({text: "{products>Rating}"})
}));
oTable.bindRows("products>/Products")
var ele = [oMatrix,oTable,oLayout]
return ele;
}
});
I tried different URI and I think the create function is ok...Advices?
Thank you for the help

Related

set document.cookie in firefox addon in contentScript

I want to set some cookie inside firefox addon contentScipt:
// Content Script ( js/firefox.js )
self.port.on("start", function() {
var request;
document.cookie = "name=value; path=/;";
request = new XMLHttpRequest();
request.open('GET', '/', true);
request.send(null);
});
But when I see request headers and cookies there is nothing about cookie 'name'.
Is it possible to add cookie inside contentScipt?
Main addon script looks like this
// Main Addon Script ( js/index.js )
var data = require("sdk/self").data;
var button = require("sdk/ui/button/toggle").ToggleButton({
id: "button",
label: "button",
icon: "./img/icon/16.png",
onChange: handleChange
});
var panel = require("sdk/panel").Panel({
contentURL: data.url("popup.html"),
contentScriptFile: data.url("js/firefox.js"),
position: button,
onHide: handleHide
});
function handleChange(state) {
if (state.checked) {
panel.show({
position: button
});
}
}
function handleHide() {
button.state('window', {checked: false});
}
panel.on("show", function () {
panel.port.emit("start");
});
Try:
self.port.on("start", function() {
var request;
unsafeWindow.document.cookie = "name=value; path=/;";
request = new XMLHttpRequest();
request.open('GET', '/', true);
request.send(null);
});

How to bind a WebGrid in a PartialView, which is in JQueryUI ModalPopup

I have this PartialView, which is loaded from the Layout of an MVC4 application.
On a button click in the main navigation menu the method SearchCustomers is called in an ajax post (shown below). Everything seems to work. Fiddler shows Data is coming back as supposed however the grid is not visible in the Popup. I wonder what am I doing wrong?
The Partial View
#model Invoice.Web.ViewModels.SearchCustomerWindowVM
<h2>Search Results</h2>
<div id="resultsGrid">
#{
if (Model.CustomersList != null)
{
var grid = new WebGrid(Model.CustomersList, rowsPerPage: 6, ajaxUpdateContainerId:"searchResults ");
#grid.GetHtml(
fillEmptyRows: true,
alternatingRowStyle: "alternate-row",
headerStyle: "grid-header",
footerStyle: "grid-footer",
mode: WebGridPagerModes.All,
firstText: "<< First",
previousText: "< Prev",
nextText: "Next >",
lastText: "Last >>",
columns: new [] {
grid.Column("Forename", canSort: false),
grid.Column("Surname"),
grid.Column("PostCode"),
grid.Column("",
header: "Actions",
format: #<text>
#Html.ActionLink("Edit", "Edit", new { id=item.CustomerID} )
|
#Html.ActionLink("Delete", "Delete", new { id=item.CustomerID} )
</text>
)
}
)
}
}
The Ajax Post - I guess the problem is here!!
<script>
$( "#searchCustomers" ).dialog({
autoOpen: false,
height: 350,
width: 700,
modal: true
});
$("#searchButton")
.button()
.click(function() {
$("#searchCustomers").dialog("open");
});
function searchCustomers() {
var forename = $("#Forename").val();
var surname = $("#Surname").val();
var postCode = $("#PostCode").val();
debugger;
var request = {
foreName: forename,
surName: surname,
postCode: postCode
};
$.ajax({
type: "POST",
url: "/Customer/SearchCustomers",
data: JSON.stringify(request),
datatype: "JSONP",
contentType: "application/json; charset=utf-8",
success: function (returndata) {
// if (returndata.ok) {
//$.post(data.Url, function(partial) {
// $('#IdOfDivToUpdate').html(partial);
$("#searchCustomers").dialog("open");
//alert("The File Has Been Downloaded.");
$('#resultsGrid').html(returndata);
//} else {
// window.alert('Error Saving Authorisation.');
//}
}
}
);
}
</script>
The Controller method:
public ActionResult SearchCustomers(string postCode, string surName, string foreName)
{
var model = new SearchCustomerWindowVM();
var modelList = new List<SearchCustomerWindowVM>();
var customersList = _customerRepository.GetAllCustomers().ToList();
foreach (var cust in customersList)
{
model.Forename = cust.FirstName;
model.Surname = cust.Surname;
model.PostCode = cust.ContactDetails.PostCode;
modelList.Add(model);
}
return Json(modelList);
// return Json(new {error = true, message = "all good."});
}
As you see I have tried other approaches in the Ajax post, which I have commented out.
Thanks in advance.
on your controller change the return to partial view
return PartialView("_PartialName", model);
then in the success of your ajax call
$('#searchCustomers').html(result);
$("#searchCustomers").dialog("open");
this way you load the div with the partial view and then open the dialog

How do I build a grid of PortfolioItem/Features with associated User Stories that have no children?

I want to create a custom grid on My Dashboard of User Stories under a portfolio item without child stories.
A custom grid on My Dashboard with Object: PortfolioIetm Feature and query UserStories.DirectChildrenCount = 0
it will produce this error:
Could not parse: Attribute "UserStories" on type PortfolioItems is not allowed in query expressions.
Here is a custom App SDK 2 app that builds a grid of Features with user stories where DirectChildrenCount = 0. It accesses the collection of stories on every feature
var stories = feature.getCollection('UserStories');
but populates the grid only with those stories that have no children. Here is the full App.html code that can be pasted into a custom tab:
<!DOCTYPE html>
<html>
<head>
<title>GridExample</title>
<script type="text/javascript" src="/apps/2.0rc1/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function () {
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
Ext.create('Rally.data.WsapiDataStore', {
model: 'PortfolioItem/Feature',
fetch: ['FormattedID','Name','UserStories'],
pageSize: 100,
autoLoad: true,
listeners: {
load: this._onDataLoaded,
scope: this
}
});
},
_createGrid: function(features) {
this.add({
xtype: 'rallygrid',
store: Ext.create('Rally.data.custom.Store', {
data: features,
pageSize: 100
}),
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
},
{
text: 'Name', dataIndex: 'Name'
},
{
text: 'Story Count', dataIndex: 'StoryCount'
},
{
text: 'User Stories', dataIndex: 'UserStories',
renderer: function(value) {
var html = [];
Ext.Array.each(value, function(userstory){
html.push('' + userstory.FormattedID + '')
});
return html.join(', ');
}
}
]
});
},
_onDataLoaded: function(store, data){
var features = [];
var pendingstories = data.length;
//debugger;
Ext.Array.each(data, function(feature) {
var f = {
FormattedID: feature.get('FormattedID'),
Name: feature.get('Name'),
_ref: feature.get("_ref"),
StoryCount: feature.get('UserStories').Count,
UserStories: []
};
var stories = feature.getCollection('UserStories');
stories.load({
fetch: ['FormattedID'],
callback: function(records, operation, success){
Ext.Array.each(records, function(story){
var number = story.get('DirectChildrenCount');
if (number == 0) {
f.UserStories.push({_ref: story.get('_ref'),
FormattedID: story.get('FormattedID')
});}
}, this);
--pendingstories;
if (pendingstories === 0) {
this._createGrid(features);
}
},
scope: this
});
features.push(f);
}, this);
}
});
Rally.launchApp('CustomApp', {
name:"GridExample"
//parentRepos:""
});
});
</script>
<style type="text/css">
.app {
/* Add app styles here */
}
</style>
</head>
<body></body>
</html>

Post Data to the action result when Dropdown list change in ASP.NET MVC using jqgrid

I have Created JqGrid for loading some records like below.
<script type="text/javascript">
$(document).ready(function () {
$('#jqgRequests').jqGrid({
defaults: {
recordtext: "View {0} - {1} of {2}",
emptyrecords: "No Request Found",
loadtext: "Loading...",
pgtext: "Page {0} of {1}"
},
//url from wich data should be requested
url: '#Url.Action("LoadRequest")',
//type of data
datatype: 'json',
//url access method type
mtype: 'POST',
//columns names
colNames: ['Is Approved','Requestor', 'Request Type', 'Request Date', 'Approved Date', 'Package','Comments','RequestID', '','',''],
//columns model
colModel: [
{ name: 'IsApproved',
formatter: function (cellvalue, options, rowObject) {
var status = rowObject[0];
if (status == 1) {
return '<input type="checkbox" name="approval" checked disabled="disabled">';
}
else if(status==2) {
return '<img src="#Url.Content("~/Content/images/reject.jpg")"></img>';
}
else{
return '<input type="checkbox" name="approval" disabled="disabled" >';
}
},sortable:false, align: 'center', width: 80, index: 'subColumn'
},
{ name: 'Requestor', index: 'Requestor', width: 170, align: 'left' },
{ name: 'Request Type', index: 'RequestType', width: 90, align: 'left' },
{ name: 'RequestDate', index: 'RequestDate', formatter: 'date', formatoptions: { srcformat: 'FullDateTime', newformat: 'd/m/Y g:i:s A' }, width: 120, align: 'left' },
{ name: 'ApprovedDate', index: 'ApprovedDate', formatter: 'date', formatoptions: { srcformat: 'FullDateTime', newformat: 'd/m/Y g:i:s A' }, width: 120, align: 'left' },
{ name: 'Package', index: 'Package', width: 150, align: 'left' },
{ name: 'Comments', index: 'Comments', width: 300, align: 'left' },
{ name: 'RequestID', index: 'RequestID', width: 1, align: 'left',hidden:true },
{ name: 'Approve',
formatter: function (cellvalue, options, rowObject) {
var status = rowObject[0];
if(status==1)
{
return '#Html.ActionLink("Approve", null, null, new { #style = "color:blue;font-weight:bold;", onclick = "return WarningPopup('Already approved');", href = "#" })';
}
else{
var x = '#Html.ActionLink("Approve", null, null, new { #style = "color:Blue;font-weight:bold;", onclick = "return ConfirmPopup('myId');", href = "#" })';
// var x = '#Html.ActionLink("Approve", "Approve", "Dashboard", new { requestId = "myId" }, new { #style = "color:Blue;font-weight:bold;", onclick = "return confirm('Are you sure to approve this request?');" })';
return x.replace("myId",rowObject[7]);
}
},sortable:false, align: 'left', width: 45
},
{ name: 'Reject',
formatter: function (cellvalue, options, rowObject) {
var status = rowObject[0];
if(status==2)
{
return '#Html.ActionLink("Reject", null, null, new { #style = "color:blue;font-weight:bold;", onclick = "return WarningPopup('Already rejected');", href = "#" })';
}
else{
var x = '#Html.ActionLink("Reject", null, null, new { #style = "color:Blue;font-weight:bold;", onclick = "return Rejectpopup('myId');", href = "#" })';
// var x = '#Html.ActionLink("Reject", "Reject", "Dashboard", new { requestId = "myId" }, new { #style = "color:Blue;font-weight:bold;", onclick = "return confirm('Are you sure to reject this request?');" })';
return x.replace("myId",rowObject[7]);
}
},sortable:false, align: 'left', width: 60
},
{ name: 'More',
formatter: function (cellvalue, options, rowObject) {
// var x = "<a class='btnMore' onclick='GetDetail('myId');' style = 'color:blue;font-weight:bold;' href='#'>More Detail</a>"
var x='#Html.ActionLink("Detail", null, null, new { #style = "color:blue;font-weight:bold;", onclick = "return GetDetail('myId');", href = "#" })';
return x.replace("myId",rowObject[7]);
},sortable:false, align: 'left', width: 80
}
],
//pager for grid
pager: $('#jqgpRequests'),
//number of rows per page
rowNum: 25,
//initial sorting column
sortname: 'RequestID',
//initial sorting direction
sortorder: 'asc',
//we want to display total records count
viewrecords: true,
//grid height
height: '100%'
});
});
</script>
Action Result
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult LoadRequest(JqGridRequest request)
{
int totalRecords = _dashboardRepository.RequestCount;
var response = new JqGridResponse()
{
TotalPagesCount = (int)Math.Ceiling((float)totalRecords / (float)request.RecordsCount),
PageIndex = request.PageIndex,
TotalRecordsCount = totalRecords
};
const string subColumn = "";
foreach (var dashboard in _dashboardRepository.LoadAllRequests(request.SortingName, request.SortingOrder.ToString(), request.PageIndex, request.RecordsCount))
{
response.Records.Add(new JqGridRecord(dashboard.RequestID.ToString(), new List<object>()
{
dashboard.IsApproved,
dashboard.Requestor,
dashboard.RequestType,
dashboard.RequestDate,
dashboard.ApprovedDate,
dashboard.Package,
dashboard.Comments,
dashboard.RequestID
}));
}
return new JqGridJsonResult { Data = response };
}
This jqGrid load when the page load. Also i have added a dropdown list for filtering. For this i need to post some parameters for the JqGridRequest class . How can i possible this?
Assuming that your dropdown id is ddlFilter you can write the JavaScript change event handler like this:
$('#ddlFilter').on('change', function(e) {
$('#jqgRequests').setGridParam({ postData: { FilterValue: $(this).val(); } }).trigger('reloadGrid', [{ page: 1 }]);
});
On server side you can create following view model for handling the post data:
public class PostDataViewModel
{
public string FilterValue { get; set; }
}
And add it as one more parameter to your action:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult LoadRequest(JqGridRequest request, PostDataViewModel postData)
{
...
}
Unless there is some specifc requirement or edge case you haven't describe in your question this should do the trick.
If I understand you correct you can follow the suggestion from the old answer.
If you have for example <select id="mySelect">...</select> on the page you can use jqGrid option
postData: {
myFilter: function () {
return $("#mySelect option:selected").val();
}
}
to send the value of the select box together with other standard jqGrid parameters (see JqGridRequest). If you want additionally to reload the grid after every changes of the select you can use .trigger("reloadGrid"). You need just set change and keyup event handler and calls .trigger("reloadGrid") it it require. See the answer for more code example.

Linked jQuery sortable lists and Backbone collections

I'm still finding my way with Backbone and I've always use Prototype instead of jQuery in the past so please forgive me if I'm doing something stupid.
I'm trying to develop a UI containing several connected unordered lists where each sortable list is represented by a separate Backbone collection. I'm using ICanHaz and Mustache templates but that's not of importance for my question.
When dragging items between the lists, how would I best achieve the automatic updating of the collections (remove a model from one and insert it into another)? I'm currently trying to use the receive and remove methods in the jQueryUI Sortable interaction — am I at least on the right lines?
var WS = {};
(function(ns) {
ns.Item = Backbone.Model.extend();
ns.Content = Backbone.Collection.extend({
model: ns.Item,
url: location.href,
initialize: function(el) {
this.el = $(el);
this.deferred = this.fetch();
},
recalculate: function() {
var count = this.length;
this.el.next(".subtotal").html(count);
},
setOrder: function() {
$.ajax({
url: this.url + "/reorder",
type: "POST",
data: "tasks=" + $(this.el).attr("id") + "&" + this.el.sortable("serialize")
});
}
});
ns.ContentRow = Backbone.View.extend({
tagName: "li",
className: "item",
events: {
"click .delete": "destroy"
},
initialize: function(options) {
_.bindAll(this, "render", "destroy");
this.model.bind("change", this.render);
this.model.view = this;
},
render: function() {
var row = ich.item(this.model.toJSON());
$(this.el).html(row);
return this;
},
destroy: function() {
if (confirm("Really delete?")) {
this.model.destroy({
success: function(model, response) {
$(model.view.el).remove();
},
error: function(model, response) {
console.log(response);
}
});
}
}
});
ns.ListView = Backbone.View.extend({
initialize: function(collection) {
this.el = collection.el;
this.collection = collection;
this.collection.bind("add", this.addOne, this);
_.bindAll(this, "addOne");
this.el.sortable({
axis: "y",
connectWith: ".tasks",
receive: _.bind(function(event, ui) {
// do something here?
}, this),
remove: _.bind(function(event, ui) {
// do something here?
}, this),
update: _.bind(function(event, ui) {
var list = ui.item.context.parentNode;
this.collection.setOrder();
}, this)
});
},
insert: function(item) {
var prefix = this.el.parentsUntil('ul').parent().attr("id"),
view = new ns.ContentRow({
model: item,
id: prefix + "_" + item.id
});
this.el.append(view.render().el);
},
addOne: function(item) {
if (item.isNew()) {
item.save({}, {
success: _.bind(function(model, response) {
// I should set id from JSON response when live
model.set({ id: this.collection.length });
this.insert(model);
}, this)
});
} else {
this.insert(item);
}
},
addAll: function() {
this.collection.each(this.addOne);
},
render: function() {
this.collection.deferred.done(_.bind(function() {
this.addAll();
}, this));
}
});
ns.AppView = Backbone.View.extend({
lists: [],
initialize: function(holder) {
holder.find("ul").each(_.bind(function(index, list) {
var Items = new WS.Content(list),
App = new WS.ListView(Items);
App.render();
this.lists.push(Items);
}, this));
}
});
})(WS);
$(document).ready(function() {
var App = new WS.AppView($("#tasks"));
});
You are on the right track. You will probably want to add the id of each sortable element into the template somewhere. Then when you receive the event, you know which model to add or remove from the collection. For example add...
<div data-id={{id}}> ... my thing ... </div>
And in the sortable call get the target's id attribute and call Collection.add() or remove()
Just use Backbone.CollectionView.. it has this functionality built in out of the box.
var listView = new Backbone.CollectionView( {
el : $( "#list1" ),
sortable : true,
sortableOptions : {
connectWith : "#list2"
},
collection : new Backbone.Collection
} );
var listView = new Backbone.CollectionView( {
el: $( "#list2" ),
sortable : true,
sortableOptions : {
connectWith : "#list1"
},
collection : new Backbone.Collection
} );

Resources