MVC3 Webgrid formatting - asp.net-mvc-3

I am using Webgrid for paging. Is there a way to access each item? For example, i want to add some links column if the the item of the model meets a certain criteria.
For example:
#grid.GetHtml(columns: grid.Columns(
/If (item.name == "test")// statement to test condition here{
grid.Column(format: (item) => Html.ActionLink("Delete", "Delete", new { name = item.name })),
}
else{
grid.Column(format: (item) => Html.ActionLink("Detail", "Detail", new { name = item.name })),
}
grid.Column("FirstName"),
grid.Column("LastName"),
grid.Column("EmailAddress")
)
can this be done with webgrid? if not, what are other alternatives?

You should be able to put a condition like that inside the format parameter itself. Like this:
#grid.GetHtml(columns: grid.Columns(
grid.Column(format: item =>
(item.name == "test") ?
Html.ActionLink("Delete", "Delete", new { name = item.name })
: Html.ActionLink("Detail", "Detail", new { name = item.name })
))
)
Note that, if you need to for a more complex scenario, you can also put an anonymous function inside the format lambda. It should return an MvcHtmlString (as in ActionLink, etc):
grid.Column(format: item =>
{
if (item.name == "test")
{
return Html.ActionLink("Delete", "Delete", new { name = item.name });
}
else
{
return Html.ActionLink("Detail", "Detail", new { name = item.name });
}
})

Related

React hooks one checkbox checked to uncheck other checkbox

Hi I have a parent component which contains a bunch child components which are checkboxes.
parent component is something like this inside:
const [items, setItems] = useState([
{
id:1,
selected: false,
},
{
id:2,
selected: false,
}
]);
const changeSelected = (id) =>
{
items.forEach((item)=>
{
if (item.id === id)
{
item.selected = !item.selected;
}
else{
item.selected = false;
}
})
}
return(
<div>
{items.map((item)=>{
<Child item={item} changeSelected={changeSelected}/>
})}
</div>
)
and in the child component, it has something like this inside:
return(
<div>
<input type="checkbox" checked={props.item.selected} onChange={()=>{props.changeSelected(props.item.id)}} />
</div>
)
I know partially this isnt working is because useState is async but I dont know what to do to make it work, or if I should try a different approach? Thank you
You can refactor your function to this:
const changeSelected = (id) => {
setItems(prev => ([...prev, {id, selected: !prev.filter(x => x.id === id)[0].selected}]))
}
Obviously I forgot to setItem according to the two answers I received. But I think the right way to do it is to make a deep copy of my existing items, and setItems again. For my future reference, here is what I have now working (an example):
let newItems = [...items];
newItems.forEach((item)=>
{
if (item.id === id)
{
item.selected = !item.selected;
}
else{
item.selected = false;
}
})
setProducts(newItems);
You are not updating the state anywhere. You should make a copy of the array and then change the object you want to:
const changeSelected = (id) =>
{ let newItems = [];
items.forEach((item)=>
{
if (item.id === id)
{
newItems.push({ id : item.id , selected : item.selected });
}
else{
newItems.push({ id : item.id , selected : false });
}
})
setItems(newItems);
}
Call setItems to set it.
Note:
Not related to the question but you should use unique keys when iterating over list.
{items.map((item)=>{
<Child key={item.id} item={item} changeSelected={changeSelected}/>
})}

How to use #pnp/sp to query a person column in an SP list to get the name

I have a web part that which needs to retrieve the Name property of a person column (a people picker) so I can populate state with it and subsequently populate a field. Here's the function that queries the item:
private _jeChange = (ev: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, index?: number) => {
this.setState({
SelectedJE: option.text,
}, () => {
const selJE = this.state.SelectedJE;
if (selJE && selJE.length > 0) {
let _item = this.state.MyListItems.find((item) => {
return item.JobRef == selJE;
});
this.setState({
JEDeptContact: _item.DeptContactId,
}, () => {
sp.web.lists.getByTitle("MyList").items.getById(_item.Id).select("DeptContact", "Lookup/Name", "Lookup/ID").expand("Lookup").get().then((item: any[]) => {
console.log(item);
});
});
}
});
}
The _item.DeptContactId successfully populates the state with the Id of the user in the person column, but I want the Name not the Id, how would I resolve the Id to the Name? Do I need to use expand to get the Name? If so how?
I've read this but I don't know where to use the expand:
https://pnp.github.io/pnpjs/sp/items/
Found it:
if(_item.DeptContactId){
sp.web.getUserById(_item.DeptContactId).select("Title", "DeptContact/Title").expand("DeptContact").get().then(r => {
this.setState({
JEDeptContact: r.Title,
});
});

Redux reducer correct way to check if item already exists in state

I'm a little uncertain of this approach when updating an existing or adding a new object to a redux store but am having trouble getting this to work using the accepted methods i.e. Object.assign, update() or spread operators. I can get it working as follows:
const initialState = {
cart: []
}
export default function cartReducer(state = initialState, action) {
switch (action.type) {
case ADD_TO_CART:
let copy = _.clone(state.cart);
let cartitem = _.find(copy, function (item) {
return item.productId === action.payload.productId;
});
if (cartitem) {
cartitem.qty = action.payload.qty;
} else {
copy.push(action.payload);
}
return {
...state,
cart: copy
}
default:
return state
}
}
Although this works, I'm using Underscore to copy the state and check whether the item already exists in state which seems unnecessary and overkill?
This is the code for the redux. Use the .find function to find if an element is already in the array.
Example Code:
const inCart = state.cart.find((item) =>
item.id === action.payload.id ? true : false
);
return {
...state,
cart: inCart
? state.cart.map((item) =>
item.id === action.payload.id
? { ...item, qty: item.qty + 1 }
: item
)
: [...state.cart, { ...item, qty: 1 }],
};
With Redux-Toolkit you can mutate the state objects so you can likely simplify this a bit.
const basket = createSlice({
name: "cart",
initialState,
reducers: {
addToCart: (state, { payload }) => {
const inCart= state.cart.find((item) => item.id === payload.id);
if (inCart) {
item.qty += payload.qty;
} else {
state.items.push(payload);
}
},
},
});

How to filter/sort OpenUI5 Grid by column, which is nested in the json?

I'm now testing the capabilities of this grid and I'm having a look at this example at the moment.
Last week, I tried some basic loading of data, returned from the controller of the MVC app that I'm working on. It returns json, which I then give to the grid to be displayed.
The data, that I want to show, is stored in multiple tables. For now, I load data from only two of them for simplicity, because I'm only testing the capabilities of the grid - will it suit our needs.
The data, which arrives at the grid (in js), looks something like this:
{
Cars: [
{
car_Number: '123',
car_Color: 'red',
car_Owner: Owner: {
owner_ID: '234',
owner_Name: 'John'
},
car_DateBought: '/Date(1450648800000)/'
},
{
car_Number: '456',
car_Color: 'yellow',
car_Owner: Owner: {
owner_ID: '345',
owner_Name: 'Peter'
},
car_DateBought: '/Date(1450648800000)/'
},
{
car_Number: '789',
car_Color: 'green',
car_Owner: Owner: {
owner_ID: '567',
owner_Name: 'Michael'
},
car_DateBought: '/Date(1450648800000)/'
}
]
}
Here is some sample code of what I have done so far:
$.ajax({
type: 'post',
url: BASE_HREF + 'OpenUI5/GetAllCars',
success: function (result) {
var dataForGrid = result['rows'];
debugger;
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData(dataForGrid);
var oTable = new sap.ui.table.Table({
selectionMode: sap.ui.table.SelectionMode.Multi,
selectionBehavior: sap.ui.table.SelectionBehavior.Row,
visibleRowCountMode: sap.ui.table.VisibleRowCountMode.Auto,
minAutoRowCount: 10,
//visibleRowCount: 10,
showNoData: false
});
// define the Table columns and the binding values
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({
text: "ID of car"
}),
template: new sap.ui.commons.TextView({ text: "{car_Number}" }),
sortProperty: "car_Number", // https://sapui5.netweaver.ondemand.com/sdk/test-resources/sap/ui/table/demokit/Table.html#__2
filterProperty: "car_Number"
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Color of car" }),
template: new sap.ui.commons.TextView({ text: "{car_Color}" }),
sortProperty: "car_Color",
filterProperty: "car_Color"
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Car Owner ID" }),
template: new sap.ui.commons.TextView({
// does not work like this -> text: "{Owner.owner_ID}"
text: {
path: 'Owner',
formatter: function (owner) {
return owner !== null ? owner['owner_ID'] : '';
}
}
}),
sortProperty: "Owner.owner_ID", // these two don't work
filterProperty: "Owner.owner_ID"
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Car Owner Name" }),
template: new sap.ui.commons.TextView({
// does not work like this -> text: "{Owner.owner_Name}"
text: {
path: 'Owner',
formatter: function (owner) {
return owner !== null ? owner['Name'] : '';
}
}
}),
sortProperty: "Owner.owner_Name", // these two don't work
filterProperty: "Owner.owner_Name"
}));
var dateType = new sap.ui.model.type.Date({ // http://stackoverflow.com/questions/22765286/how-to-use-a-table-column-filter-with-formatted-columns
pattern: "dd-MM-yyyy"
});
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Date bought" }),
template: new sap.ui.commons.TextView({
text: {
path: 'car_DateBought',
formatter: dateFormatterBG
}
}),
sortProperty: "car_DateBought",
filterProperty: "car_DateBought",
filterType: dateType
}));
oTable.setModel(oModel);
oTable.bindRows("/");
oTable.placeAt("testTable", "only");
},
error: function (xhr, status, errorThrown) {
console.log("XHR:");
console.log(xhr);
console.log("Status:");
console.log(status);
console.log("ErrorThrown:");
console.log(errorThrown);
}
});
My problems:
I cannot sort or filter the list of cars by owner_ID or owner_Name. How should I do the filtering and sorting? Should it be done with the help of a formatter function in some way, or...?
I can sort by car_DateBought, but I cannot filter the cars by this field. First, I tried setting filterType: dateType, then I tried setting it to filterType: dateFormatterBG(it turns out, that dateType does exactly the same thing as my own dateFormatterBG does, btw).
function dateFormatterBG(cellvalue, options, rowObject) {
var formatedDate = '';
if ((cellvalue != undefined)) {
var date = new Date(parseInt(cellvalue.substr(6)));
var month = '' + (date.getMonth() + 1);
var day = '' + date.getDate();
var year = date.getFullYear();
if (month.length < 2) {
month = '0' + month;
}
if (day.length < 2) {
day = '0' + day;
}
formatedDate = [day, month, year].join('-');
}
return formatedDate;
}
Anyway, as I said, I tried both, but it doesn't work. When I click on the header of a column like in the example in the first link, I don't get any sort of a datepicker. How can I tell OpenUI5, that this column needs to be filtered by date and it should provide the user with a datepicker, when he/she clicks on the 'Filter' input field at the bottom of the dropdown menu? When I try to write the date in the filter field like '07-11-2016' (the way it is formatted), I get an empty table/grid. If I try to enter the huge number from field car_DateBought in the json object, all available rows in the table stay the same and when I reclick on the header, the filter field at the bottom of the dropdown menu appears with error-state.
Thank you in advance for your help and pieces of advice!
Edit:
This is just sample, dummy data. I try to load the real data and I see, that in the table I've got a couple of rows with date, which is today (07-11-2016, or 11/7/2016 if you prefer). That's why getting an empty table after trying to filter means it's not working correctly.
Sorting: in a sample I am looking at the following appears in the controller:
onInit : function () {
this._IDSorter = new sap.ui.model.Sorter("my_id", false);
},
....
Then in the view there is a button defined in the header column as
<Column>
<Label text="Project"/>
<Button icon="sap-icon://sort" press="onSortID" />
</Column>
And back in the controller there is a further function:
onSortID: function(){
this._IDSorter.bDescending = !this._IDSorter.bDescending;
this.byId("table").getBinding("items").sort(this._IDSorter);
},
I read this collectively as defining a sorter in the onInit(), then toggle/reversing it in the click event of the sort button in the column header via the onSortId() function. The OpenUI5 API doc re sorters indicates there are more parameters in the sorter constructor for initial sort direction and sorting function.
Following this pattern, for your needs to sort on the owner_ID or owner_Name, I assume you could set up a sorter as
this._OwnerIDSorter = new sap.ui.model.Sorter("car_Owner/owner_ID", false);
this._OwnerNameSorter = new sap.ui.model.Sorter("car_Owner/owner_Name", false);

sortdir not working on enum data type in MVC 3 WebGird

I have the following structure:
Model
public class EventEntry : LogEntry
{
public EventType Type { get; set; }
public string Source { get; set; }
}
public enum EventType : int
{
Information = 1,
Warning = 2,
Error = 3
}
View
<div id="grid">
#{
var grid = new WebGrid(canPage: true, rowsPerPage: Ctrl.PageSize, canSort: true, ajaxUpdateContainerId: "grid");
grid.Bind(Model.Events, rowCount: Model.TotalRecords, autoSortAndPage: false);
grid.Pager(WebGridPagerModes.All);
#grid.GetHtml(htmlAttributes: new { id="grid" },
columns: grid.Columns(
grid.Column("Type"),
grid.Column("Source"));
}
</div>
Controller
public ActionResult Index(int? page, string sort, string sortdir) {...}
When I click on "Source" column that is of type string, the sordir will change from "ASC" to "DESC" but when I try the same thing on the "Type" column sordir will always return "ASC".
The current accepted answer is not the answer to your problem.
It appears that enums are not sorted when you do not mention the columnname in the bind operation. I fixed this by providing all the required column names when binding my model to the webgrid. The UserType property is an enumeration in this example.
var webgrid = new WebGrid(rowsPerPage: 25);
webgrid.Bind(Model, new[] { "FirstName", "MiddleName", "SurName", "UserType" });
var columns = webgrid.Columns(
webgrid.Column("FirstName", "Voornaam"),
webgrid.Column("MiddleName", "Tussenvoegsels"),
webgrid.Column("SurName", "Achternaam"),
webgrid.Column("UserType", "Type gebruiker"),
);
So I reckon that the sorting will work without changing your controller if you implement to following code:
<div id="grid">
#{
var grid = new WebGrid(canPage: true, rowsPerPage: Ctrl.PageSize, canSort: true, ajaxUpdateContainerId: "grid");
grid.Bind(Model.Events, new[] { "Type", "Source" }, rowCount: Model.TotalRecords, autoSortAndPage: false);
grid.Pager(WebGridPagerModes.All);
#grid.GetHtml(htmlAttributes: new { id="grid" },
columns: grid.Columns(
grid.Column("Type"),
grid.Column("Source"));
}
</div>
Try setting the Grid.SortColumn with the last sorted column.
Controller code
ViewData["lastsortedcol"] = Request["sort"];
View code.
var grid = new WebGrid();
grid.Bind(source: userItems.PagedSet, rowCount: userItemsForSale.TotalCount,autoSortAndPage:false);
grid.SortColumn = (string)ViewData["lastsortedcol"] ;
Response.Write(grid.GetHtml(
columns: grid.Columns
(
grid.Column(columnName: "ItemName", header: "ItemName", format: (item) => Html.Label(((UserItemForSale)item.Value).ItemDetails.Name)),
grid.Column(columnName: "Quantity", header: "Quantity", format: (item) => Html.Label(((UserItemForSale)item.Value).Qty + ""))
)
));
I have had this happen a number of times; specifically when binding an enumeration type to a column.
I found that you can get round this issue (although this is a serious cludge) by changing the ColumnName value to the name of an unused, non-enumeration type property and then setting it to the correct value in your controller before using it:
E.g. - this fails:
grid.Column("PaymentMethod", "Loan Delivery Method", item => string.Format("{0}", EnumHelper.GetFirstValueFromMetaDataAttribute(item.PaymentMethod, Constants.GENERALMETADATATAG))),
Then change it to something like:
grid.Column("WaitForDocsNoOfRetries", "Loan Delivery Method", item => string.Format("{0}", EnumHelper.GetFirstValueFromMetaDataAttribute(item.PaymentMethod, Constants.GENERALMETADATATAG))),
In my controller method I then do:
sort = sort == "WaitForDocsNoOfRetries" ? "PaymentMethod": sort;

Resources