确保我的扩展列表始终显示“当前”数据?

时间:2012-04-03 14:27:21

标签: tridion

当您为CME列表创建数据扩展器时 - 例如为this example中的模式添加列 - 只要您执行强制重新加载列表的操作,这一切都可以正常工作。

但是,某些操作不强制列表重新加载(比如编辑文件夹中的组件,然后保存和关闭),看起来Anguilla正在加载使用仅加载的不同机制更改的项目的数据有问题的项目的数据(这是有道理的)。

如果我希望我的扩展列表视图行为正常,并且每当给定项目发生更改时(而不是仅在重新加载列表视图时)还加载我的附加属性,我还需要做什么?

4 个答案:

答案 0 :(得分:13)

我发现安圭拉如何处理这件事。当您实现数据扩展器时,您正在扩展有关列表中显示的项目的信息,这基本上意味着您正在扩展相关项目后面的数据(模型)。

Tridion中的每个Item在Anguilla Framework中都有自己的类,例如Component有自己的Tridion.ContentManager.Component javascript“class”。

说完这个,回到显示组件模式名称的示例,我们实际上并没有扩展模型,因为该信息已经在组件中可用。但是,我们需要覆盖每个用于在项目所在列表中显示信息的方法,在本例中为Component。

因此,当我们处理Data Extender时,如果我们想要完全实现此功能,我们不仅需要定义数据扩展器:

<ext:dataextender 
    name="IntelligentDataExtender" 
    type="Com.Tridion.PS.Extensions.IntelligentDataExtender,PS.GUI.Extensions">
    <ext:description>Shows extra info</ext:description>
</ext:dataextender>

但我们还需要定义我们添加的列:

<ext:lists>
    <ext:add>
        <ext:extension name="IntelligentColumnExtender"   
                       assignid="IntelligentDataColumnExtender">
          <ext:listDefinition>
            <ext:selectornamespaces/>
            <ext:columns>
              <column 
                  xmlns="http://www.sdltridion.com/2009/GUI/extensions/List"
                  id="IntelligentData" 
                  type="data"  
                  title="Additional Info" 
                  selector="@ExtendedInfo" 
                  translate="String"/>
            </ext:columns>
          </ext:listDefinition>
          <ext:apply>
            <ext:view name="DashboardView" />
          </ext:apply>
        </ext:extension>
      </ext:add>
  </ext:lists>

一旦我们有了这个,GUI将显示我们刚刚添加的列:“其他信息”

好吧,现在我们需要在编辑/签出项目等时刷新清单...

为此,我们需要扩展模型并在我们扩展的Object中实现一些方法。在这个例子中,我正在扩展Page对象,因此无论何时编辑页面,我们要更新的列表中的行都会与表中的其余单元格一起刷新。

要扩展模型,我们需要定义我们扩展的类型,在本例中我将使用“Page”类作为示例。首先,您需要在编辑器的配置文件中定义模型扩展名:

<cfg:group name="Com.Tridion.PS.Extensions.UI.Model"
     merger="Tridion.Web.UI.Core.Configuration.Resources.DomainModelProcessor" 
     merge="always">
    <cfg:domainmodel name="Com.Tridion.PS.Extensions.UI.Model">
      <cfg:fileset>
        <cfg:file type="script">/Scripts/PSPage.js</cfg:file>            
      </cfg:fileset>
      <cfg:services />
    </cfg:domainmodel>
</cfg:group>

<ext:modelextensions>
  <cfg:itemtypes>
    <cfg:itemtype id="tcm:64" implementation="Com.Tridion.PS.Extensions.UI.PSPage" />        
  </cfg:itemtypes>
</ext:modelextensions>

正如您所看到的,我通过使用Javascript文件“/Scripts/PSPage.js”中定义的“Com.Tridion.PS.Extensions.UI.PSPage”类来扩展页面。

处理行刷新的唯一方法如下:

Com.Tridion.PS.Extensions.UI.PSPage.prototype.getListItemXmlAttributes 
= function PSPage$getListItemXmlAttributes(customAttributes) {
    var attribs = {};
    var p = this.properties;   

    if (customAttributes) {
        for (var attr in customAttributes) {
            attribs[attr] = customAttributes[attr];
        }
    }
    //This adds my custom column back when the item is updated
    attribs["ExtendedInfo"] = p.extendedInfo;

    return this.callBase(
        "Tridion.ContentManager.Page", 
        "getListItemXmlAttributes", 
        [attribs])
};

正如您所看到的,我正在实现“ExtendedInfo”属性,该属性是我附加列中显示的属性。

在处理向列表中添加列时,不仅仅是添加Data Extender。我将在my blog here写一篇文章,提供一个完整的例子。

我希望这是有道理的。

答案 1 :(得分:6)

嗯,Jaime正确描述了CME如何更新列表中的项目。但我想添加一些关于List控件,域模型List和Items如何相互交互的附加信息。这可能有助于您构建具有类似功能的扩展。

大多数域模型列表项都继承自Tridion.ContentManager.ListTcmItems类。在加载任何基于提到的类的List项时,它将在Lists Registry中注册(并在卸载List时未注册)。这将允许Model使用已注册的列表作为Items的静态数据源,并更新这些列表中更改的Items数据。

更新项目静态数据

例如,我们已加载ListCategories,列表中只有一个类别:

var pub = $models.getItem("tcm:0-1-1");
var list = pub.getListCategories();
list.load();

// After list is loaded
list.getXml();

getXml()返回类似(简化)的XML:

<tcm:ListCategories>
    <tcm:Item ID="tcm:1-4-512" Type="512" Title="Keys" />
</tcm:ListCategories>

之后,如果您尝试获取类别“Keys”的某些静态数据,则它已经设置:

var category = $models.getItem("tcm:1-4-512");
category.isLoaded();         // return false
category.isStaticLoaded();   // return false
category.getTitle();         // return undefined
category.getStaticTitle();   // return "Keys"!

这是可能的,因为$models.getItem调用会做两件事:它将返回一个现有的(或创建一个新的)域模型对象,并用它调用$models.updateItemData方法。此方法调用将遍历列表注册表中的所有已注册列表以及TimeStamp大于Item的Last Update TimeStamp将使用模型对象调用list.updateItemData的所有列表。

updateItemData方法将检查传递的项目是否在列表中,如果是,则将使用列表中可用的静态数据更新项目。

更新列表中已更改项目的数据

当修改(更新,删除,创建新的)域模型项时,会调用以下方法之一:

  • $models.itemUpdated
  • $models.itemRemoved

这些方法将通过列表注册表中的列表并调用list.itemUpdated(或list.itemRemoved)。这些方法将检查是否传递Item包含在它们的List中,如果是,它们将从Item数据更新List xml。

为此目的,getListItemXmlNode类中有Tridion.ContentManager.Item方法。此方法将基于Item上的getListItemXmlAttributes方法提供的属性数组构建List xml节点。这就是Jaime在回答中提到的。

如果更新了List xml,将在List对象上触发其中一个事件:

  • itemadd
  • itemupdate
  • itemremove

在视图中的List对象上收听这些事件,可以及时更新列表控件。

因此,如果您希望此机制适用于您的扩展程序,请坚持以下规则:

  • 如果您要创建新的域模型List对象 - 它应该继承Tridion.ContentManager.ListTcmItems类,或者它应该实现getId()itemUpdated(item)itemsUpdated(item)itemRemoved(item)updateItemData(item)方法
  • 如果要查看List控件中的更改 - 将处理程序附加到域模型List对象上的相应事件并更新List控件
  • 如果要创建新的域模型项 - 它应该继承Tridion.ContentManager.Item类,您应该改进getListItemXmlAttributes方法以返回列表的正确属性数组

答案 2 :(得分:2)

CME确实会在保存发生后动态更新列表中的项目,而无需前往服务器。

为此,它调用名为“getListItemXml”的方法,该方法返回列表的更新XML元素。然后,它将更新或添加此元素,该元素将在列表视图中更新或添加项目。

getListItemXml是不同Model对象的方法。

那你怎么利用这个呢?我不确定。

也许您可以使用自己的方法覆盖该方法(或者最好使用getListItemXmlAttributes)来添加其他数据?

只要在列表中更新项目,就会触发“itemupdate”事件。 你可以通过做这样的事情来解决这个问题:

var myEventHandler = function(event)
{
    $log.message("Item updated. TridionEvent object passed: " + event);
}

var view = $display.getView();
var list = view.getListObject("uri-of-Folder");
list.addEventListener("itemupdate", myEventHandler);

我想你可以用它来更新事后的项目列表条目。 一定要在某些时候调用removeEventHandler。

这显然不是最佳选择。 但我不知道任何可以解决这一特定问题的扩展点。

答案 3 :(得分:0)

我想我会(尝试)通过定期监视文件夹中的项目并在此轮询机制检测到该文件夹​​中的更改后更新该列表来实现此目的。

例如,我会写一些在后台运行的javascript超时或间隔,并检查当前文件夹中的项目。如果它检测到更改,则会触发更新列表。

或者,您也可以尝试拦截更改列表的操作(例如创建新项目),也可以通过事件系统拦截,并更新您的列表。我不认为这与第一种方法有很大的不同,因为我认为它仍然意味着从GUI端进行一定程度的轮询。