I have a question on how JSF 1.2 manages DataTable exactly. Consider this table (suppose that tableList.persone has 3 items):
<h:dataTable id="tablePersone" value="#{tableList.persone}" var="item">
<h:column>
<f:facet name="header">
<h:outputText value="STATO" />
</f:facet>
<h:inputText value="#{item.stato}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="CODICE" />
</f:facet>
<h:inputText value="#{item.codice}" />
</h:column>
</h:dataTable>
I read that jsf iterates over the items of the list during the render response phase, in fact, "item" is not available when the view is built.
Does it means that jsf does not duplicate the content of the table for each item in the list when creating the tree component?
In the table above, each row has 2 inputText. If jsf does not create a couple of inputText objects for each row, how jsf handles all the 6 request parameters when the form is submitted (in particular during the apply request values phase).
Thanks a lot,
Nico
If I am not wrong
Restore View phase - in this phase retrieves the component tree for the requested page if it was displayed previously or constructs a new component tree if it is displayed
for the first time. If the page was displayed previously, all components are set
to their prior state. This means that JSF automatically retains form information.
For example, when a user posts illegal data that is rejected during decoding,
the inputs are redisplayed so that the user can correct them.
Apply Request Values phase- In this phase, the JSF
implementation iterates over the component objects in the component tree. Each
component object checks which request values belong to it and stores them.
Process Validations phase, the submitted string values are first converted
to “local values,” which can be objects of any type. When you design a JSF
page, you can attach validators that perform correctness checks on the local
values. If validation passes, the JSF life cycle proceeds normally. However,
when conversion or validation errors occur, the JSF implementation invokes
the Render Response phase directly, redisplaying the current page so that the
user has another chance to provide correct inputs.
Update Model Values phase- in this phase the
local values are used to update the beans that are wired to the components.
Invoke Application phase the action method of the button or link component
that caused the form submission is executed
Render Response phase - encodes the response and sends it to the
browser.
I'm using Tridion 2011 (with DD4T, feeding an MVC webapp).
It seems that MetaData fields for Multimedia Components (specified on the Metadata tab of my Images Schema in Tridion) are not populating the corresponding property on the DD4T "Component" object. e.g. LinkedComponentFields[0].MetadataFields is empty and Multimedia.AltText is null.
Specifically the field I'm after is the AltText. But as the entire MetadataFields collection is empty on the Component, it's obviously not pulling through any metadata properties. i have tried using TemplateBuilder to set parameters in the Component Template (I set "resolve width and height" to yes, and the MergeAction to Merge) - this did not help.
Any ideas?
It is possibly caused by the linklevel. By default, links are followed for one level from the page or component that you are publishing.
You can increase this by adding a parameter to the template invocation, called linklevel. Try it with a value of 2 first, then increase until it works.
When you create a Data Extender for a CME list – for instance to add a column for the Schema as in this example – it all works fine and dandy whenever you do actions that force a List reload.
However, some actions don’t force a list reload (like editing a component in a folder, then saving & closing) and it looks like Anguilla is loading the data for the item that changed using a different mechanism that loads only the data for the item in question (which makes sense).
If I would want my extended list view to behave properly and also load my additional attributes whenever a given item changes (instead of only when the list view is reloaded) what else do I need to do?
I found how Anguilla takes care of this. When you implement a Data Extender, you are extending the information regarding the items displayed in the list, which basically means that you are extending the Data (Model) behind the item in question.
Each Item in Tridion has its own class in the Anguilla Framework, for example a Component has its own Tridion.ContentManager.Component javascript "class".
Having said this, and going back to the example that shows the schema name of the component, we are not actually extending the model, since that information is already available in the component. However, we need to overwrite the methods exposed on each used for displaying information in the lists the item is in, in this case a Component.
So, when we deal with a Data Extender, if we want a full implementation of this functionality, we not only need to define the data extender:
<ext:dataextender
name="IntelligentDataExtender"
type="Com.Tridion.PS.Extensions.IntelligentDataExtender,PS.GUI.Extensions">
<ext:description>Shows extra info</ext:description>
</ext:dataextender>
But also we need to define what's the column we are adding:
<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>
Once we have this, the GUI will display the column we just added: "Additional Info"
Well, now we need to achieve the list refreshing when the item is edited/checked-out and in, etc...
For that, we need to extend the model and implement a few methods in the Object we are extending. In this example I am extending the Page object, so whenever a page is edited, the row in the list we want to update gets refreshed, together with the rest of the cells in the table.
To extend the model we need to define what types are we extending, in this example I am going to use the "Page" class as an example. First of all you need to define the model extension in the config file of your Editor:
<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>
and
<ext:modelextensions>
<cfg:itemtypes>
<cfg:itemtype id="tcm:64" implementation="Com.Tridion.PS.Extensions.UI.PSPage" />
</cfg:itemtypes>
</ext:modelextensions>
As you can see I am extending the Page by using the "Com.Tridion.PS.Extensions.UI.PSPage" class that is defined in the Javascript file "/Scripts/PSPage.js".
The only method that handles the row refreshing is the following:
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])
};
As you can see I am implementing the "ExtendedInfo" attribute which is the one displayed in my additional column.
There's more than just adding a Data Extender when dealing with adding a column to our lists. I will write a post in my blog here to provide with a fully working example.
I hope it makes sense.
Well, Jaime correctly described how CME updates changed items in Lists. But I want to add some additional information on how List controls, domain model List and Items are interact with each other. This might help you building your own extension with similar functionality.
Most of the domain model List items inherit from Tridion.ContentManager.ListTcmItems class. On the moment when any List item, based on mentioned class, is loaded it will be registered in Lists Registry (and un-registered when the List is unloaded). This will allow Model to use registered Lists as source of static data for Items and to update changed Items data in these Lists.
Update Item static data
For example, we have loaded ListCategories and there is only one Category in the List:
var pub = $models.getItem("tcm:0-1-1");
var list = pub.getListCategories();
list.load();
// After list is loaded
list.getXml();
That getXml() returns an XML like (simplified):
<tcm:ListCategories>
<tcm:Item ID="tcm:1-4-512" Type="512" Title="Keys" />
</tcm:ListCategories>
After that, if you try to get some static data for Category "Keys" it will be already set:
var category = $models.getItem("tcm:1-4-512");
category.isLoaded(); // return false
category.isStaticLoaded(); // return false
category.getTitle(); // return undefined
category.getStaticTitle(); // return "Keys"!
That is possible because $models.getItem call will do two things: it will return an existing (or create a new) domain model object and call $models.updateItemData method with it. This method call will go through all registered Lists in the Lists Registry and for all Lists whose TimeStamp bigger than Item's Last Update TimeStamp will call list.updateItemData with the model object.
The updateItemData method will check if the passed Item is in the list and if it is, then the Item will be updated with the static data that is available from the List.
Updating data of changed Items in the List
When a domain model Item is modified (updated, removed, created new) one of these methods is called:
$models.itemUpdated
$models.itemRemoved
These methods will go through the Lists in Lists Registry and call list.itemUpdated (or list.itemRemoved). These methods will check is passed Item is contained in their List and if so they will update the List xml from the Item data.
For that purpose there is a getListItemXmlNode method in the Tridion.ContentManager.Item class. This method will build List xml node based on the array of attributes, provided by getListItemXmlAttributes method on the Item. That's what Jaime mentioned in his answer.
If the List xml was updated, one of these events will be fired on List object:
itemadd
itemupdate
itemremove
Listening to these events on a List object in your view will allow you to timely update your List Control.
So if you want this mechanism to work with your extension, stick to these rules:
If you are creating new domain model List object - it should inherit Tridion.ContentManager.ListTcmItems class or it should implement the getId(), itemUpdated(item), itemsUpdated(item), itemRemoved(item) and updateItemData(item) methods
If you want to see changes in List control - attach handlers to corresponding events on the domain model List object and update your List control
If you are creating new domain model Item - it should inherit Tridion.ContentManager.Item class and you should improve getListItemXmlAttributes method to return correct array of attributes for the List
The CME will indeed update the items in the list dynamically after the save occurs, without going to the server.
To do so, it calls a method named "getListItemXml" which returns the update XML element for the list. It will then update or add this element, which will update or add the item in the list view.
getListItemXml is a method of the different Model objects.
So how do you take advantage of this? I'm not sure.
Perhaps you could overwrite the method (or maybe getListItemXmlAttributes is best) with your own to add the additional data?
There is also an "itemupdate" event fired whenever an item is updated in the list.
You can hook into that by doing something like this:
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);
I suppose you could use that to update the list entry for the item after the fact.
Be sure to call removeEventHandler at some point too.
None of this is optimal, obviously.
But I don't know of any extension point that would solve this particular problem.
I think I would (attempt to) implement this by monitoring the items in a folder periodically and updating that list after this polling mechanism had detected a change in that folder.
For example, I would write some javascript timeout or interval that runs in the background and checks the items in the current folder. If it detects a change, it triggers the update of the list.
Alternatively, you could also try to intercept the action that changed your list (e.g. the creation of a new item), maybe by means of an event system, and as such update your list. I don't think this is much different than the first approach, as I think it still implies some level of polling from the GUI side.
How to get FaceletContext from FaceletContext in JSF 1.2?
The problem is that I am creating a Tab dynamically and I want to include a view inside the newly created Tab. Including a view is supported only by FaceletContext.
Maybe with
FacesContext.getCurrentInstance().
getELContext().getContext(FacelectContext.class)
See ELContext#getContext(java.lang.Class)
Returns the context object associated with the given key.
I have some incoming XML documents, I need to check attributes that are configurable in this coming XML and if the attribute is not there in the XML document being checked add it.
The attributes to be checked will be specified in the app.config file
OrderRequest.orderDetails.orderSummary.testCount, I need to check if the testCount attribute exists under the element OrderRequest. If No add it along with it’s value which is also specified in the app.config
INCOMING XML --> Read the attributes from the app.config which need to be checked in this XML file --> Read the incoming XML using XDocument --> If the attribute is not there in the incomg XML add it to the XML.
Any ideas how I can go on this.
I wrote a series of articles on how to create custom configuration sections, which can be found here: http://dotnetslackers.com/articles/CustomConfiguration/default.aspx
Is this a static development task? What I mean is, are you only testing the testCount attribute, or is this generic to say loop through the element type and check all of its attributes to ensure they are there?
Either way, essentially you have to find an element, get its name, access your custom configuration section and lookup the name, use the GetAttribute method to check for attribute existence, and append a new attribute to the element if not.
HTH.