I am adding a notes field to the grid of AP202000 (Vendor Prices) and when I enter something and hit save, it doesn't stick. I have added the NoteIndicator="True" to the grid on the AP202000 Page and I have added this code to the APVendorPrice DAC, not as an extension:
#region NoteID
public abstract class noteID : PX.Data.IBqlField
{
}
protected Guid? _NoteID;
[PXNote]
public virtual Guid? NoteID
{
get
{
return this._NoteID;
}
set
{
this._NoteID = value;
}
}
#endregion
Here is the code for the grid header:
<px:PXGrid ID="grid" runat="server" DataSourceID="ds" Height="144px" Style="z-index: 100" Width="100%" Caption="Sales Prices"
SkinID="Details" FilterShortCuts="True" NoteIndicator="True" FilesIndicator="True" ActivityIndicator="True" AdjustPageSize="Auto" AllowPaging="True" SyncPosition="true" >
I noticed other forums where it said if I would do these two things then the notes field would work, however this is not my case. This is for the note field to be on the grid with each row and would save to each individual row on the grid, not the notes field at the top.
Related
I am selecting multiple lines (ctrl/shift+click) from the grid on the Sales Order screen and want an action to have access to what was selected. How do I access the list of what's selected on the grid from the code behind?
As stated, add the selected screen. First you would add a DAC extension to add the selected field, which is not a DB field.
#region Selected
[PXBool]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
public abstract class selected : PX.Data.BQL.BqlBool.Field<selected> { }
#endregion
From there, you can add the selected field to your table in the UI. Also, ensure that commit changes is set on that field, or an action that you may call to query.
Finally, you can just run a foreach for the view, and check for the selected field you added:
foreach (SOLine line in Base.Transactions.Select())
{
SOLineExt lineExt = line.GetExtension<SOLineExt>();
if (line.Selected == true)
{
//execute code on the record
}
}
I am using ZKOSS MVVM.
So in View I am using a Listbox and it's bound (#load) to a list model object in ViewModel.
What I understand from documentation, if I change the model
1: Add an object to list model from View Model at index 0
I should see the latest object be appended at top of the Listbox.
2: Remove an item from model
I should see that particular row from Listbox be removed.
Note: It's an interface like social network e.g. Facebook wall when someone create a post and new post is appended to the posts list. If a post is deleted only that post is deleted from the list
Well, it does happen (new item gets appended/deleted item gets removed) but the whole Listbox reloads and not just that particular row which was added or removed.
Why is that? Why Listbox reloads fully on list model change.
Any idea?
Here are the code snippets (Use Case: Add new post is applicable. On creating new post whole Listbox reloads every time):
View
<z:div style="height: 100%; padding: 0px; margin: 0px;" apply="org.zkoss.bind.BindComposer"
viewModel="#id('want_vm') #init('want.WantDesktopVM')">
<z:div zclass="content">
<g:render template="../css/list/noEffectList"></g:render>
<z:div hflex="1" width="100%" visible="#load(want_vm.toggleInput)" style="margin-bottom: 5px; padding: 5px">
<z:vbox>
<z:textbox id="postInput" multiline="true" value="" width="690px" height="50px"/>
<z:div hflex="1" width="100%" style="text-align: right; padding-right: 5px">
<z:button label="Post" zclass="button rect theme" onClick="#command('post', text=postInput.value)"/>
</z:div>
</z:vbox>
</z:div>
<z:listbox model="#load(want_vm.posts)" emptyMessage="No new posts found." style="border:none;">
<z:template name="model" var="iwant">
<listitem style="margin-top: 10px">
<listcell>
<hbox hflex="true">
<div zclass="dpFrame small">
<image height="50px" width="50px" content="#load(iwant.from) #converter('converter.UserActorDisplayPicConverter')" />
</div>
<vbox hflex="true" zclass="post">
<hbox hflex="true">
<label value="#load(iwant.from) #converter('converter.ActorDisplayNameConverter')" zclass="displayName"/>
</hbox>
<hbox hflex="true">
<label value="#load(iwant.textData)" zclass="post_data" multiline="true" maxlength="25"/>
</hbox>
<hbox>
<label value="#load(iwant.dateCreated) #converter('converter.SinceDateConverter')" zclass="since"/>
</hbox>
</vbox>
</hbox>
</listcell>
</listitem>
</z:template>
</z:listbox>
</z:div>
ViewModel
class WantDesktopVM {
UserActorManagerService userActorManagerService
ActivityManagerService activityManagerService
UserActor me
UserActor profile
String error = null
String view = 'iwant'
#Wire
Textbox postInput
private List<Activity> posts = []
#Init
public void init(#ContextParam(ContextType.COMPONENT) Component component,
#ContextParam(ContextType.VIEW) Component view) {
profile = Executions.current.getAttribute("profile")
me = Executions.current.getAttribute("me")
loadPosts()
}
#AfterCompose
public void afterCompose(#ContextParam(ContextType.VIEW) Component view) {
Selectors.wireComponents(view, this, false);
}
public boolean isMyProfile() {
return me.id == profile.id
}
public UserActor getMe() {
return this.me
}
public boolean isToggleInput() {
return this.view == 'iwant' && isMyProfile()
}
public List<Activity> getPosts() {
println "Getting posts ...${posts.size()}"
return this.posts
}
private List<Activity> loadPosts() {
if(view == 'iwant') {
posts = Activity.createCriteria().list() {
eq 'from', profile
eq 'type', ACTIVITY_TYPE.WANT
order("lastUpdated", "desc")
}
} else {
posts = ActorActivitySpace.createCriteria().list() {
projections {property("activity")}
eq 'actor', profile
activity {
ne 'from', profile
eq 'type', ACTIVITY_TYPE.WANT
}
order("lastUpdated", "desc")
}
}
return posts
}
#NotifyChange(['posts', 'toggleInput'])
#Command
public void render(#BindingParam('view') String view) {
println "Changing view ..."
this.view = view
loadPosts()
}
#NotifyChange('posts')
#Command
public void post(#BindingParam('text') String text) {
println "Posting text: $text"
postInput.setValue("")
if(text) {
Activity want = activityManagerService.want(me.id, text)
println"Want ID : $want.id"
posts.addAll(0, [want])
}
}
}
You use #NotifyChange('posts') to tell ZK that the whole list has changed. The grid doesn't try to examine the list, it simply replaces its current ListModel with the new list -> full reload.
If you don't want that, you will have to use the methods of the ListModel used by the grid to update the ui. That way, the grid will know exactly which rows have changed and only update those.
[EDIT] To achieve what you want, replace List<Activity> posts with ListModelList<Activity> posts = new ListModelList<Activity>()
When the activities change, you must update this list (i.e. call add() or addAll()) to update individual rows. You can no longer load everything from the database, you must merge changes in the database with the existing list.
I have created a custom checkbox template field by deriving it from System.Web.UI.WebControls.TemplateField. The template for this field has been created by creating a class which implements ITemplate interface. When any postback happens on the page the values in the checkboxes is lost.
To get this working temporarily I have used viewstate to store the state of checkboxes in the checkbox column, but going further I want to completely avoid this as I will be using more template fields in same fashion in my application.
Please let me know if I am missing anything.
Following is the code:
namespace MyControls
{
public class CheckBoxTemplateField : TemplateField
{
public CheckBoxTemplateField()
{
this.HeaderTemplate = new CheckBoxTemplate();
this.ItemTemplate = new CheckBoxTemplate();
}
}
public class CheckBoxTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
CheckBox chk = new CheckBox();
container.Controls.Add(chk);
}
}
}
Regards,
Gaurav
checkbox is known with their problem maintaining their value in postback
1 solution is to store its value in hidden fiesld and to read it in server.
p.s. thhis has nothing to do with viewstate.input control doesnt saves their value in viewstate ( excpet textbox which has the 'ontextchange' event)
I am using a DevExpress ASPxGridView containing column GridViewDataComboBoxColumn.
The combo box is working correctly in edit mode (allows AJAX style filtering; it inserts, updates and deletes correctly).
The only problem is that in display mode it is displaying the ValueField (numeric id) instead of the TextField.
<dx:GridViewDataComboBoxColumn Width="200px" FieldName="LocationKeyUid" VisibleIndex="0" Caption="Index">
<PropertiesComboBox EnableCallbackMode="true" CallbackPageSize="7" IncrementalFilteringMode="StartsWith"
OnItemsRequestedByFilterCondition="ItemsRequestedByFilterCondition" OnItemRequestedByValue="ItemsRequestedByValue"
TextField="KeyValue" ValueType="System.Int32" TextFormatString="({0}) {1}" ValueField="LocationKeyUid" />
As shown above, I've tried different experiments with setting the TextFormatString, but that seems to be ignored.
I am binding as follows:
IList<LocationKeyGridViewModel> locationKeys = GetLocationKeys();
locationKeyGridView.DataSource = locationKeys;
locationKeyGridView.DataBind();
The class property names (below) are assigned to the TextField and ValueField property settings (above).
public class LocationKeyGridViewModel
{
public int LocationKeyUid { get; set; }
public string KeyValue { get; set; }
}
I have tried changing the FieldName property assignment to the TextField assignment
(i.e. KeyValue) but that generates an Input string is not in correct format error.
Is there something obvious here that I am missing?
Here is my situation -
I have two nested view models:
<%=Html.EditorFor(x => x.DisplayEntitiesWithRadioboxesViewModel)%><br />
Which sit within their parent (StructureViewModel), I can populate the nested ViewModels easily and pass it through to the main View:
Within the Controller - Example
var moveDepartment = new StructureViewModel();
moveDepartment.DisplayEntitiesWithRadioboxesViewModel = fullDepartmentList.Select(x => new DisplayEntityViewModel
{
Id = x.Id,
Path = x.Path,
PathLevel = x.PathLevel,
Description = x.Description,
});
return View(moveDepartment);
EditorTemplete - Example
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Site.Areas.Administration.ViewModel.DisplayEntityViewModel>>" %>
<table class="aligncenter"><%
if (Model != null)
{
foreach (var entity in Model)
{%>
<tr class="tRow">
<td style="text-align:left; text-indent:<%=Html.Encode(entity.PathLevel)%>em">
<%=Html.Encode(entity.Description)%>
<%=Html.RadioButton("radiobutton",entity.Id)%>
</td>
</tr><%
}
}%>
</table>
namespace Site.Areas.Administration.ViewModel
{
public class DisplayEntityViewModel
{
public int Id { get; set; }
public string Path { get; set; }
public string PathLevel { get; set; }
public string Description { get; set; }
}
}
However when I try to pull back this information the nested ViewModels are null:
[HttpPost]
public ActionResult Move(StructureViewModel StructureViewModel)
When I hover over StructureViewModel it only contains data set at the parent ViewModel. For example: a hidden value can been seen but DisplayEntitiesWithRadioboxesViewModel = null.
The only way I know how to access the DisplayEntitiesWithRadioboxesViewModel is to use FormCollection and iterate throught the FormCollection and pull out the information I need from the nested ViewModels.
This however just doesn't seem right, as I have found at I then have to re-populate the DisplayEntitiesWithRadioboxesViewModel with the values from the FormCollection, if for example an error has occured and the user needs to be sent back to the same View.
I have tried searching the web/books but cannot find a solution.
Is there a better way?
Thanks in advance for any help.
And why did you use an EditorFor for a
simple dropdown, which is easily to
use with DropDownFor
This has now been altered to use the DropDownFor.
what is the Key of the
DisplayEntitiesWithRadioboxesViewModel
value in FormCollection
{string[3]}
[0] = "DisplayEntitiesWithRadioboxesViewModel.radiobutton"
[1] = "Action"
[2] = "OldParentId"
Clare :-)
Your problem is pretty common and somewhat easy to fix once you understand how it works.
Right now you have a view model that has a property which is an IEnumerable<T> (doesn't matter what the generic parameter is). You are trying to pass the items to the view and populate the IEnumerable<T> with the same values when the response comes back, using the values originally written to the page, and augmented with the selected item (at least from the code you have posted anyway, it would help for you to state your exact intention in the question). The problem you have here is that you must send those values to the page in a way in which they can be returned.
Let me just say now that you probably should NOT be using this technique. It is typically a much better idea to return the selection only and generate the list again if you need to server side.
From the looks of things, you want to return the whole list and then look for the item that is selected, which is after all the point of a drop down or radio button group. In order to get the selection back, the parameter to your controller action must have properties which match the variables passed back in. In this case, it looks like you are using the parameter name radiobutton for all of your radio buttons (the same hold true for drop down list, only it uses the name of the list). Which ever one is selected, the value associated with it is returned with that name. The MVC framework takes care of trying to find the appropriate action which has as many names specified as possible.
What you need to use for your action parameter is a new class that contains a property for all of the field names being submitted back to the server! Or of course you could simply add the radiobutton property to your StructureViewModel too. In fact, you'll notice that it is trying to set that value already, only it doesn't currently exist on your view model. You still will not receive the original list back however, but thats okay, because even if you did receive the original list back, you have no identifier on it to let you know which item was selected!
Hopefully this helps you understand what is going on, if you have more questions, please ask.
I would recommend you using strongly typed helpers everywhere so that you don't have to worry about naming your controls. Here's how to proceed:
Models:
public class DisplayEntityViewModel
{
public int Id { get; set; }
public string Path { get; set; }
public string PathLevel { get; set; }
public string Description { get; set; }
}
public class StructureViewModel
{
public IEnumerable<DisplayEntityViewModel> DisplayEntitiesWithRadioboxesViewModel { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var moveDepartment = new StructureViewModel();
moveDepartment.DisplayEntitiesWithRadioboxesViewModel = new[]
{
new DisplayEntityViewModel
{
Id = 1,
Path = "some path 1",
PathLevel = "some path level 1",
Description = "some description 1"
},
new DisplayEntityViewModel
{
Id = 2,
Path = "some path 2",
PathLevel = "some path level 2",
Description = "some description 2"
},
};
return View(moveDepartment);
}
[HttpPost]
public ActionResult Index(StructureViewModel StructureViewModel)
{
return View(StructureViewModel);
}
}
Main View (~/Views/Home/Index.aspx):
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<SomeNs.Models.StructureViewModel>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm()) { %>
<table class="aligncenter">
<%= Html.EditorFor(x => x.DisplayEntitiesWithRadioboxesViewModel) %>
</table>
<input type="submit" value="Go" />
<% } %>
</asp:Content>
Editor Template (~/Views/Home/EditorTemplates/DisplayEntityViewModel.ascx)
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ToDD.Models.DisplayEntityViewModel>" %>
<tr class="tRow">
<td style="text-align:left; text-indent:<%=Html.Encode(Model.PathLevel)%>em">
<%= Html.Encode(Model.Description) %>
<!-- Remember that you need to place input fields for each property
that you expect to get back in the submit action
-->
<%= Html.HiddenFor(x => x.Description) %>
<%= Html.TextBoxFor(x => x.Path) %>
</td>
</tr>
Now submit the form and everything should be bound correctly. An important thing to note is that the editor template is strongly typed to DisplayEntityViewModel and not IEnumerable<DisplayEntityViewModel> as in your case. When in your main view you write:
<%= Html.EditorFor(x => x.DisplayEntitiesWithRadioboxesViewModel) %>
the framework automatically detects that the property is a collection and will call the editor template for each item of this collection so you no longer need to loop through the elements which makes your code more elegant.
UPDATE:
Using dropdown lists is also very easy: checkout this answer.
Can you tell me how the EditorFor looks exactly? And why did you use an EditorFor for a simple dropdown, which is easily to use with DropDownFor.
what is the Key of the DisplayEntitiesWithRadioboxesViewModel value in FormCollection
If I understand it correctly, you have a View, with some parent-info, and at the same time multiple iterations of these 2 fields in the same view. Is that right?
Then I know how to fix this.