PDA

View Full Version : [CLOSED] No Cls in ListItem?



michaeld
Nov 17, 2013, 2:22 AM
Why is it ListItems in the various controls do not have a class attribute? I'm trying to bind simple list items to a multiselect or combo but there seems no way to highlight an individual li based on my own criteria. I don't want to have to build the complex logic for a store just to use a template so I can add a class. I've observed others on the forums have been frustrated by this deficiency in extjs.

Is there a simple way? or a feature request I can pose?

michaeld
Nov 17, 2013, 2:29 AM
Also, I'm finding I cannot write a function that populates ListItems generically for both a MultiSelect and ComboBox even though they both share in common Items and SelectedItems. This would be nice. Even an interface in common could do the trick.

geoffrey.mcgill
Nov 17, 2013, 2:47 PM
Thanks for making these suggestions. We are investigating both.

Daniil
Nov 19, 2013, 1:09 PM
Hi,

1. ListItem Cls.

Well, I agree it would be good to have. But it is not such simple to implement as it might seem. It would involve client and server functions.

Yes, there is the built-in store/template mechanism to achieve the requirement. You say it is too complex, but it doesn't look that complex. What do you think about this example?

Example

<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>

<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
Store store = this.ComboBox1.GetStore();
store.DataSource = new object[]
{
new object[] { "1", "Item 1", "item1" },
new object[] { "2", "Item 2" },
new object[] { "3", "Item 3", "item3" }
};
}
}
</script>

<!DOCTYPE html>

<html>
<head runat="server">
<title>Ext.NET v2 Example</title>

<style>
.item1 {
color: yellow;
}

.item3 {
color: green;
}
</style>
</head>
<body>
<form runat="server">
<ext:ResourceManager runat="server" />

<ext:ComboBox
ID="ComboBox1"
runat="server"
DisplayField="text"
ValueField="value">
<Store>
<ext:Store runat="server">
<Model>
<ext:Model runat="server">
<Fields>
<ext:ModelField Name="value" />
<ext:ModelField Name="text" />
<ext:ModelField Name="cls" />
</Fields>
</ext:Model>
</Model>
<Reader>
<ext:ArrayReader />
</Reader>
</ext:Store>
</Store>
<ListConfig>
<ItemTpl runat="server">
<Html>
<div class="{cls}">{text}</div>
</Html>
</ItemTpl>
</ListConfig>
</ext:ComboBox>
</form>
</body>
</html>


2. A common parent control for ComboBox and MultiSelect.

Well, yes, they both have some similar functionality like Items and SelectedItems, but they are different controls anyway. We cannot see a good possibility to have a common parent control for them. Moreover, our policy is to reflect the client side components hierarchy as much as possible.

michaeld
Nov 20, 2013, 1:15 AM
1. ListItem Cls.

Well, I agree it would be good to have. But it is not such simple to implement as it might seem. It would involve client and server functions.

Yes, there is the built-in store/template mechanism to achieve the requirement. You say it is too complex, but it doesn't look that complex. What do you think about this example?


Yeah, I already looked at the example in the example explorer and found the same option, and yes, I am aware that these controls are about passing only data down to the client and that extjs is the cause of this inherent limitation. I realized it would be a massive effort to extend extjs just to support ListItems with more dom support of the li. Not even System.Web.UI.WebControls.ListItem does this (which I've always felt was a bad design).

I anticipated the resistance to implement but decided to wait to see what you had to say first. I ended up doing the following in my code:


X.AddScript( string.Concat( MS.ClientID, ".el.select('li:last').addCls('MenuFix');" ) ); /// where MS is the multiselect


This only worked because the item I wanted to highlight was always going to be at the end of the list, but my problem would have been more severe if I needed to find the li in the dom based on the value or the text.

What if we were to pose a middle solution? How about a client-side function that allows a search for the ListItem dom based on text or the value? Say getListItem()
Example:


X.AddScript( string.Concat( MS.ClientID, ".getListItem(", value, ").addCls('MenuFix');" ) ); /// where MS is the multiselect



2. A common parent control for ComboBox and MultiSelect.

Well, yes, they both have some similar functionality like Items and SelectedItems, but they are different controls anyway. We cannot see a good possibility to have a common parent control for them. Moreover, our policy is to reflect the client side components hierarchy as much as possible.
I looked too and I realized the same problem. That is why I posed an interface. Here:


public interface IListItemControl {
ListItemCollection SelectedItems { get; }
ListItem SelectedItem { get; }
ListItemCollection Items { get; }
Type ItemsFromEnum { get; set; }
void InsertItem( int index, ListItem item );
void InsertItem( int index, string text, object value );
void AddItem( string text, object value );
void AddItem( ListItem item );
void RemoveByIndex( int index );
void RemoveByValue( string value );
void RemoveByText( string text );
}

Update these...


+ public abstract partial class ComboBoxBase : PickerField, IStore<Store>, IListItemControl
{
+ // I added this just because I think it's appropriate
+ public virtual void AddItem( ListItem item ) {
+ AddItem( item.Text, item.Value );
+ }
+ public virtual void InsertItem( int index, ListItem item ) {
+ InsertItem( index, item.Text, item.Value );
+ }



}
+ public abstract partial class MultiSelectBase : Field, IPostBackEventHandler, IStore<Store>, IListItemControl
{

+ // I added this just because I think it's appropriate
+ public virtual void AddItem( ListItem item ) {
+ AddItem( item.Text, item.Value );
+ }
+ public virtual void InsertItem( int index, ListItem item ) {
+ InsertItem( index, item.Text, item.Value );
+ }


+ // You'll have to add these to client code because they don't presently exist

+ /// <summary>
+ /// Insert record
+ /// </summary>
+ /// <param name="index"></param>
+ /// <param name="values"></param>
+ [Meta]
+ [Description( "Insert record" )]
+ public virtual void InsertRecord( int index, IDictionary<string, object> values ) {
+ RequestManager.EnsureDirectEvent();
+ this.Call( "insertRecord", index, values );
+ }

+ /// <summary>
+ /// Add record
+ /// </summary>
+ /// <param name="values"></param>
+ [Meta]
+ [Description( "Add record" )]
+ public virtual void AddRecord( IDictionary<string, object> values ) {
+ RequestManager.EnsureDirectEvent();
+
+ this.Call( "addRecord", values );
+ }

+ /// <summary>
+ /// Insert item
+ /// </summary>
+ /// <param name="index"></param>
+ /// <param name="text"></param>
+ /// <param name="value"></param>
+ [Meta]
+ [Description( "Insert item" )]
+ public virtual void InsertItem( int index, string text, object value ) {
+ RequestManager.EnsureDirectEvent();
+
+ this.Call( "insertItem", index, text, value );
+ }

+ /// <summary>
+ /// Add item
+ /// </summary>
+ /// <param name="text"></param>
+ /// <param name="value"></param>
+ [Meta]
+ [Description( "Add item" )]
+ public virtual void AddItem( string text, object value ) {
+ RequestManager.EnsureDirectEvent();
+
+ this.Call( "addItem", text, value );
+ }

}

Daniil
Nov 20, 2013, 6:01 AM
1. getListItem

I can suggest the following solution.

Example

<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>

<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
Store store = this.ComboBox1.GetStore();
store.DataSource = new object[]
{
new object[] { "1", "Item 1" },
new object[] { "2", "Item 2" },
new object[] { "3", "Item 3" }
};

X.Js.Call("addClsToItem", new JRawValue(this.ComboBox1.ClientID), "2", "my-item");
}
}
</script>

<!DOCTYPE html>

<html>
<head runat="server">
<title>Ext.NET v2 Example</title>

<script>
var addClsToItem = function (comboBox, value, cls) {
var rec,
picker = comboBox.getPicker();

picker.on("refresh", function(picker) {
rec = comboBox.findRecordByValue(value)
Ext.fly(picker.getNodeByRecord(rec)).addCls(cls);
});
};
</script>

<style>
.my-item {
color: red;
}
</style>
</head>
<body>
<form runat="server">
<ext:ResourceManager runat="server" />
<ext:ComboBox
ID="ComboBox1"
runat="server"
DisplayField="text"
ValueField="value">
<Store>
<ext:Store runat="server">
<Model>
<ext:Model runat="server">
<Fields>
<ext:ModelField Name="value" />
<ext:ModelField Name="text" />
</Fields>
</ext:Model>
</Model>
<Reader>
<ext:ArrayReader />
</Reader>
</ext:Store>
</Store>
</ext:ComboBox>
</form>
</body>
</html>


2. IListItemControl interface

Yes, we are thinking about it as well. Thank you.

michaeld
Nov 20, 2013, 7:15 AM
<script>
var addClsToItem = function (comboBox, value, cls) {
var rec,
picker = comboBox.getPicker();

picker.on("refresh", function(picker) {
rec = comboBox.findRecordByValue(value)
Ext.fly(picker.getNodeByRecord(rec)).addCls(cls);
});
};
</script>

This is great. Thank you.



2. IListItemControl interface

Yes, we are thinking about it as well. Thank you.

I'm sure there are many opportunities beyond this one but I'm afraid I've got tunnel vision at the moment that keeps me focused on what I'm working on at the time. As you've probably already realized, I'm keeping an eye on anything where I think ext.net can improve. I'll pose; you can tell me yes or no.

Daniil
Jan 15, 2014, 6:02 AM
2. IListItemControl interface

Yes, we are thinking about it as well.

At the moment it doesn't look worth enough to implement. Though, we will keep it in mind. Thank you for the suggestion!