【问题标题】:Making sure my extended lists always show "current" data?确保我的扩展列表始终显示“当前”数据?
【发布时间】:2012-04-17 05:30:16
【问题描述】:

当您为 CME 列表创建数据扩展器时(例如,为架构添加列,如 this example 中所示),只要您执行强制重新加载列表的操作,一切都会正常运行。

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

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

【问题讨论】:

    标签: tridion


    【解决方案1】:

    我发现安圭拉是如何处理这个问题的。实现 Data Extender 时,您正在扩展有关列表中显示的项目的信息,这基本上意味着您正在扩展相关项目背后的数据(模型)。

    Tridion 中的每个项目在 Anguilla 框架中都有自己的类,例如,组件有自己的 Tridion.ContentManager.Component javascript“类”。

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

    所以,当我们处理数据扩展器时,如果我们想要完整地实现这个功能,我们不仅需要定义数据扩展器:

    <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 将显示我们刚刚添加的列:“附加信息”

    好了,现在我们需要实现在item被编辑/签出和签入等时刷新列表...

    为此,我们需要扩展模型并在我们扩展的对象中实现一些方法。在此示例中,我扩展了 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”属性,该属性显示在我的附加列中。

    在处理向列表添加列时,不仅仅是添加数据扩展器。我将在my blog here 写一篇文章,提供一个完整的工作示例。

    我希望这是有道理的。

    【讨论】:

    • 感谢您提供数据扩展器的示例。我正在尝试创建一个数据扩展器,它应该填充我的组件的列表字段,并从查找组件中获取值。为此,我可以通过添加基本 http 类型的新绑定来建立核心服务连接。我成功建立了连接。我不知道服务参考。是否必须拥有它?如何通过 Data Extenders 指向组件页面的特定字段来填充它?请解释一下。提前致谢。感谢您尽早回复。
    • @jaime 我知道这个帖子已经很久了......但我正在使用 web8 并且仍然有同样的刷新问题。我不知道我们应该将 javascript 文件放在服务器上的哪个位置...
    • 查看我的博客,我有一个完整的示例,jaimesantosalcon.blogspot.com/2012/04/…,要完全实现数据扩展器,您需要数据扩展器以及 GUI 扩展部分。
    【解决方案2】:

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

    大多数领域模型列表项都继承自Tridion.ContentManager.ListTcmItems 类。在加载基于上述类的任何列表项时,它将在列表注册表中注册(并且在卸载列表时取消注册)。这将允许模型使用已注册的列表作为项目的静态数据源,并更新这些列表中更改的项目数据。

    更新项目静态数据

    例如,我们加载了 ListCategories,而 List 中只有一个 Category:

    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>
    

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

    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 方法。此方法调用将遍历 Lists Registry 中所有已注册的 Lists,对于 TimeStamp 大于 Item 的 Last Update TimeStamp 的所有 Lists,将使用模型对象调用 list.updateItemData

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

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

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

    • $models.itemUpdated
    • $models.itemRemoved

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

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

    如果 List xml 已更新,则会在 List 对象上触发以下事件之一:

    • itemadd
    • 项目更新
    • 项目删除

    在您的视图中侦听List 对象上的这些事件将允许您及时更新您的列表控件。

    因此,如果您希望此机制与您的扩展程序一起使用,请遵守以下规则:

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

    【讨论】:

    • 好东西,鲍里斯。一个可能的更正:category.isStaticLoaded() 在给定的示例中不会返回 true 吗?
    • @PeterKjaer 不,这将是错误的,因为您尚未加载静态数据(使用 VIEW 打开模式从 CM 加载项目的 xml)。当 Item 未加载时,某些 Item 的数据可用,这是一种例外情况。
    • 优秀的答案 Boris,我们已经为 Tridion 提议了一个专门的 Stack Exchange 站点,如果您考虑关注它,您的专业知识将非常有用? area51.stackexchange.com/proposals/38335/tridion
    • 感谢邀请。现在跟进。
    【解决方案3】:

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

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

    getListItemXml 是不同模型对象的方法。

    那么您如何利用这一点呢?我不知道。

    也许您可以用自己的方法覆盖该方法(或者最好使用 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。

    显然,这些都不是最优的。 但我不知道任何可以解决这个特定问题的扩展点。

    【讨论】:

    • 谢谢彼得,我现在会接受这个答案,因为我可以看到它会起作用。我很确定 CME 使用的一定有一种“更好”的方式,对吧?
    • 这是 CME 使用的方法。问题是它没有考虑可扩展性。使用 CME知道 的数据更新项目就好了;但是没有简单的方法来添加由扩展程序添加的数据。
    • 确实,没有“简单”的方法,但有可能。
    【解决方案4】:

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

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

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

    【讨论】:

    • 这听起来像是解决已经存在的问题(CME 今天处理它)。
    • 即使你开始应用这个“变通方法”,你也不需要从头开始实现它——在 SP1 版本中引入了 ListMonitoredItems(作为 TCM54 模型 js 代码库的一部分)。您可以轻松地将项目添加到此列表并从中删除。列表中的项目将使用配置文件中设置的超时进行监控。当监控项目之一将被更改时 - 将触发相应的事件。
    猜你喜欢
    • 1970-01-01
    • 2012-10-03
    • 2012-03-27
    • 2012-07-14
    • 2014-09-17
    • 2012-05-21
    • 2019-08-16
    • 2016-05-29
    • 2023-01-19
    相关资源
    最近更新 更多