如何利用AngularJS动态创建表格和动态赋值

如何利用AngularJS动态创建表格和动态赋值,第1张

第一步,打开HBuilder开发工具,在指定的Web项目中新建静态页面init.html,并引入Bootstrap和AngularJS相关的文件

第二步,在body元素添加ng-controller指令,并在里面添加<table></table>

第三步,在<script></script>里编写AngularJS初始化函数,并声明控制器

第四步,预览该静态页面,在浏览器查看页面效果,显示一个输入框和按钮

第五步,在控制器中添加变量model,这个变量赋值数组

第六步,在表格table循环model变量,遍历该数组并给表格赋值

注意事项

注意AngularJS动态获取表格数据

注意AngularJS动态赋值

GridView 是ASP.NET中表格数据显示控件中的一种,可以支持数据绑定,绑定的数据源我们一般用实现IEnumerable<T>接口的对象,T可以是任何一个CLR类(当然还有一些其他的数据源格式),这些大家基本都很熟悉,但是最近碰到一个新的需求:

像有一个类似于:

public class Book

{

public int ID { getset}

public string Name { getset}

public Dictionary<string, object>ExtendProperties { getset}

}

其中ExtendProperties 是用来存储不同用户自定义的扩展属性的,用键值对的形式保存,Key保存扩展属性名,Value保存扩展属性值,每个用户可能的扩展属性个数和键值都不一样。

现在,如果我们需要把List<Book>绑定在GridView上面,但是希望将ExtendProperties中的扩展属性也都显示出来,而且相应的Key显示在Column的Header,而Value则显示在相应的Cell中。

起初想沿着GridView绑定一般数据的思路考虑,看是否能够通过动态属性的方式将ExtendProperties中的键值对匹配成相应的对象属性,(没有测试是否能够成功),但是又觉得数据绑定是控件的事情,这个不应该由数据本身来负责,那我们能否通过修改GridView本身的行为来达到这个目的呢?? 答案是肯定的!

我们都知道,GridView本身是有一个AutoGenerateColumns的属性,如果设置为True的话,GridView将自动添加一些列,这些列对应Book中的每一个可绑定的属性,这里是用PropertyDescriptor来实现的(好像是考虑到DesignMode,而没有用Type来做反射)。根据这个思路,我们可以先看看AutoGenerateColumns到底对GridView有哪些影响以及GridView本身是如何生成Columns的。

通过查看GridView的源码,我们可以看到几个重要的方法

代码

protected virtual ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource)

protected virtual AutoGeneratedField CreateAutoGeneratedColumn(AutoGeneratedFieldProperties fieldProperties)

其中 CreateColumns方法是GridView用来生成列的,而在其中会根据AutoGenerateColumns属性来判断是否调用CreateAutoGenerateColumn来自动生成相应属性的列。而且这两个方法都是可以重载的,根据我们的需求,我们可以构建一个GridView的子类,重载 CreateColumns 方法,在 调用 base.CreateColumns的返回结果中插入我们希望生成的Column即可。

代码如下:

代码

#region Properties

public bool AutoGenerateExtendPropertiesColumn { getset}

public int AutoGenerateColumnsAfter { getset}

public string ExtendPropertiesDataField { getset}

#endregion

protected override ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource)

{

ICollection collection = base.CreateColumns(dataSource, useDataSource)

if (AutoGenerateExtendPropertiesColumn )

{

ArrayList list = new ArrayList()

ICollection extendPropertiesCollection = CreateExtendPropertiesColumns(dataSource, useDataSource)

ArrayList list1 = new ArrayList()

foreach (var c in collection)

{

list1.Add(c)

}

ArrayList list2 = new ArrayList()

if (extendPropertiesCollection != null)

{

foreach (var c in extendPropertiesCollection)

{

list2.Add(c)

}

}

int copyFrom = AutoGenerateColumnsAfter <list1.Count ? AutoGenerateColumnsAfter : list1.Count - 1

copyFrom = copyFrom >= 0 ? copyFrom : -1

for (int i = 0i <= copyFromi++)

{

list.Add(list1[i])

}

list.AddRange(list2.ToArray())

for (int i = copyFrom + 1i <list1.Counti++)

{

list.Add(list1[i])

}

return list

}

return collection

}

protected virtual ICollection CreateExtendPropertiesColumns(PagedDataSource dataSource, bool useDataSource)

其中我添加了几个属性和一个新的方法:

代码

public bool AutoGenerateExtendPropertiesColumn { getset}

public int AutoGenerateColumnsAfter { getset}

public string ExtendPropertiesDataField { getset}

protected virtual ICollection CreateExtendPropertiesColumns(PagedDataSource dataSource, bool useDataSource)

AutoGenerateExtendPropertiesColumn是用来判断是否要生成扩展属性对应的Column,

而 AutoGenerateColumnsAfter是用来判断将自动生成的Column应该从什么位置开始插入,

ExtendPropertiesDataField 是用来指明在绑定的对象中,哪个属性是存储扩展属性的信息的,

方法 CreateExtendPropertiesColumns是用来生成与ExtendProperties对应的Columns.

这里只是简单的举个例子,如何通过重载 CreateColumns 方法来实现自己动态添加Column 的目的。

现在我们看看如何实现 CreateExtendPropertiesColumns 方法的:

代码

protected virtual ICollection CreateExtendPropertiesColumns(PagedDataSource dataSource, bool useDataSource)

{

ArrayList array = new ArrayList()

if (dataSource.DataSourceCount >0 &&!String.IsNullOrEmpty(ExtendPropertiesDataField))

{

var enumerator = dataSource.DataSource.GetEnumerator()

enumerator.Reset()

if (enumerator.MoveNext())

{

object firstData = enumerator.Current

if (firstData != null)

{

PropertyDescriptor extendPropertiesDesc = TypeDescriptor.GetProperties(firstData).Find(ExtendPropertiesDataField, false)

if (extendPropertiesDesc != null &&typeof(IEnumerable<KeyValuePair<string, object>>).IsAssignableFrom(extendPropertiesDesc.PropertyType))

{

IEnumerable<KeyValuePair<string, object>>extendProperties = (IEnumerable<KeyValuePair<string, object>>)extendPropertiesDesc.GetValue(firstData)

if (extendProperties != null)

{

foreach (var exProperty in extendProperties)

{

ExtBouldField bouldField = new ExtBouldField()

bouldField.UseMethodBinding = true

bouldField.MethodName = "GetExtendProperty"

bouldField.MethodParam = exProperty.Key

bouldField.HeaderText = exProperty.Key

array.Add(bouldField)

}

}

}

}

}

}

return array

}

上面的代码很简单,就是根据扩展属性在对象中的属性名,获取相应的值,然后再根据扩展属性构建对应的Column,这里有一个新的自定义的 BouldField: ExtBouldField. 我们知道,一般的 BouldField 都是对对象的property进行绑定,而我们的数据存储在一个类型为 Dictionary<string,Object>的 ExtendProperties中,而且希望该Column的HeaderText是Key, Cell中显示的是Value,这个是系统的BouldField不能实现的,那我就自己实现了一个可以绑定方法的ExtBouldField (这里只是起到一个抛砖引玉的作用,功能很简单,指定一个 MethodName, 和一个暂时只能为String类型的MethodParam,这里只能为 String(或者其他基本类型),是为了能够让其在ASPX页面上直接进行设置,如果这些属性只是纯代码设置,那么MethodParam可以为任何类型).

通过分析 BouldField 的源码,可以了解到 BouldField 对每一个 DataCell 的数据获取路径大概是这样的:

InitializeCell() ->InitializeDataCell() ->OnDataBouldField() ->GetValue(),

最后的数据获取途径是 GetValue() 方法,而且 GetValue() 方法也是可以重载的,那么我们可以重载 GetValue() 方法来实现按照自己的需求(通过绑定方法而不是绑定属性的形式)来获取DataCell的绑定数据。为了考虑到原来的基于对象属性的绑定形式还可以使用,我还对 InitializeDataCell() 方法做了一些稍微的修改,该 ExtBouldField 的详细代码如下:

代码

public class ExtBouldField :BoundField

{

#region Ctor

public ExtBouldField()

: base()

{

UseMethodBinding = false

}

#endregion

#region Properties

public bool UseMethodBinding

{

get

set

}

public string MethodName

{

get

set

}

public string MethodParam

{

get

set

}

#endregion

#region Overrided methods

protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)

{

Control child = null

Control control2 = null

bool needBinding = (!UseMethodBinding &&!String.IsNullOrEmpty(DataField))

||(UseMethodBinding &&!String.IsNullOrEmpty(MethodName))

if ((((rowState &DataControlRowState.Edit) != DataControlRowState.Normal) &&!this.ReadOnly) || ((rowState &DataControlRowState.Insert) != DataControlRowState.Normal))

{

TextBox box = new TextBox()

box.ToolTip = this.HeaderText

child = box

if ((needBinding) &&((rowState &DataControlRowState.Edit) != DataControlRowState.Normal))

{

control2 = box

}

}

else if (needBinding)

{

control2 = cell

}

if (child != null)

{

cell.Controls.Add(child)

}

if ((control2 != null) &&base.Visible)

{

control2.DataBinding += new EventHandler(this.OnDataBindField)

}

}

protected override object GetValue(Control controlContainer)

{

if (UseMethodBinding)

{

if (String.IsNullOrEmpty(MethodName))

{

throw new HttpException("DataItem No MethodName")

}

object component = null

if (controlContainer == null)

{

throw new HttpException("DataControlField_NoContainer")

}

component = DataBinder.GetDataItem(controlContainer)

if (component != null)

{

MethodInfo bindingMethodInfo = component.GetType().GetMethod(MethodName)

if (bindingMethodInfo == null)

{

throw new HttpException(String.Format("Not Found the Method:{0}", MethodName))

}

return bindingMethodInfo.Invoke(component, new object[] { MethodParam })

}

return component

}

return base.GetValue(controlContainer)

}

#endregion

}

其中:

UsingMethodBinding 用来指明是用方法绑定还是原来的基于属性的绑定;

MethodName 用来指明通过绑定对象的哪个方法来获取绑定数据;

MethodParam 用来指明方法的参数(如果是代码设置该属性的话,可以让他为任何类型,但是这里只是用string,为了使ASPX页面也能直接设置该参数的值)。

到这里,原来碰到的问题都解决了:

通过继承 GridView 并且重载 CreateColumns() 添加自己想要的 Column,根据扩展属性中的键值对生成Column。

通过继承 BouldField,并且重载 InitializeDataCell() 和 GetValue() 实现自己希望的绑定方法,实现可以基于方法的数据绑定,从而可以将扩展属性中的键值绑定到对应的Cell中。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/bake/11942374.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存