displaying branched XML on a tree component in flex - apache-flex

please i have a namespaced Xml structure :
<rootlevel xmlns="http://www.wigo.org/simo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.wigo.org/wigo ./schemas/lexicon.xsd">
<name>simulation</name>
<num_vars>
<variable>
<name>BMASS_COLLECT_PROP_NAT_REM</name>
</variable>
</num_vars>
now, i have a labelFunction
that passes in the xml..as an object but when i ran the programme, the tree view has each node, name, num_vars and variable as branches but the content in each of them was null and blank.
So, my question is how can i properly display the namespaced XML on a tree view such that it shows every branches and elements in each branch?
private function treeLabel(item:Object):String{
var label:String = item.localName();
return label;
}

It might be a good idea to parse XML into a strong-typed object like in this post.

Related

Is overriding JavaFx TreeItem getChildren add a good idea?

My aim is to have a process done during all addition to children in a Tree (a TableTreeView to be precise).
The node.getTreeItem().getChildren.add(playlist) is called in different parts of my code, and I tried to keep best practices as much as possible... so let's keep it simple and say I will for sure call it while a drag'n'drop is done, as well as at the building of the tree.
My 'playlist' can be of 3 different types (in enum class) :
FOLDER (containing other playlist)
LIST (containing tracks added by user)
QUERY (containing tracks as result of a query)
MISTAKE (should never be set, but useful for debug and so)
I want to implement a method on my 'extended' TreeItem<Playlist> such as getPlaylistType().
This method would return the type of the playlist.
QUESTION :
My instinct would say I should Override the node.getTreeItem().getChildren.add(playlist) to set the type in a way :
There are children playlist --> FOLDER
No children playlist && query exists --> QUERY
No children playlist && query does not exists --> LIST
Any other state --> UNKOWN/MISTAKE
Is this approach correct ?
How to Override the 'add(...)' method ?
Why do you expose node.getTreeItem().getChildren.add(playlist) to different parts of your software? If you just wrap it in your own class you could expose that and do whatever you want when the corresponding add method is called.

generating xml containg fields of a component in sdl tridion

How to generate xml file which contain all the fields of a component in SDl Tridion?
I have to do this by writing C# code.
I am using the following code:
public class stockcompany : ITemplate
{
private Engine engine;
private Package package;
public void Transform(Engine engine, Package package)
{
this.engine = engine;
this.package = package;
StringBuilder sb = new StringBuilder();
Component component = engine.GetObject(package.GetValue("Component.ID")) as Component;
ItemFields componentfields = new ItemFields(component.Content, component.Schema);
ItemFields compometa = new ItemFields(component.Metadata, component.Schema);
if (compometa.Contains("check"))
{
}
if (componentfields.Contains("companyname"))
{
string company = string.Empty;
company = componentfields["companyname"].ToString();
package.PushItem("xml", package.CreateHtmlItem(company.ToString()));
XDocument myxml = new XDocument (new XDeclaration ("1.0","UTF-8",null ),new XElement ("companies",new XElement ("company",xml)));
}
You are probably re-inventing the wheel here.
Tridion items are XML. The .Content and .Metadata properties of a component return XML, would this be enough?
DD4T uses templates that publish XML to the delivery side, might be worth checking it: http://code.google.com/p/dynamic-delivery-4-tridion/
Given that DD4T is open sourced, you may want to check how they do it as an example.
Another approach to generating XML is to use an XmlSerializer. It works as follows:
Create a POCO
Fill it with values from the component
Use XmlSerializer to deserialize it into an XML string
Store the XML in the Output variable of the package
This is how DD4T does it. As Nuno said, it is worth while to check it out (see his answer).
I've typically resorted to XSLT to get source XML via a component template, but we can definitely do the same with C#.
[TcmTemplateTitle("Show XML Guts")]
public class ShowXmlGuts : ITemplate
{
public void Transform(Engine engine, Package package)
{
Item contentItem = package.GetByType(ContentType.Component);
Component component = engine.GetObject(contentItem.GetAsSource().GetValue("ID")) as Component;
package.PushItem("componentSource", package.CreateHtmlItem(component.Content.OuterXml));
}
}
Pick-and-Choose Fields
If at all possible, I'd start with an intermediate XML format that's not a one-to-one mapping to component source.
We're meant to get and transform fields with the appropriate APIs. Relying on the source component format could be problematic in your next major change, which could include:
schema changes and new keywords
presentation/rendering side or CMS changes
"unexpected" content (rich text, special characters, tcm references, etc)
Alternatives to C#
In terms of technology:
XSLT is great for "XML generation," even if done in a C# template building block.
The XSLT Mediator would a good choice, if allowed in your environment
You could create XML with DWT, simplifying field selection; however, it's easier to create invalid XML this way (XSLT doesn't validate your XML either, but it's slightly harder to break node nesting)
If possible, update your question with the output XML you're trying to achieve or start a new question to get from your raw component XML to desired output.
Your code isn't very clear and contains a lot of problems, but generally you seem to be on the correct track.
1) You need to cast your
componentfields["companyname"].ToString();
I suspect you're working with a TextField here so cast it to a TextField object and then use the objects .value property
2) Here is where you push the value into the package, this will contain whatever you got from your 'companyname' field, it could be xml, it may not be:
package.PushItem("xml", package.CreateHtmlItem(company.ToString()));
..But I think with this information you can find your way to what you need.
Good luck!

Bind Flex component text to xml Node text for a desktop application

I have a tabNavigator with three tabs, on 2 tab pages I have a richtext control id = "characters" and id = "worlds", and on one a textarea control id = "objects".
How do I bind these to an xml file with nodes
(root>
(characters>* //text from richtext.text id = "characters" must go here on save*(characters>
(worlds> //text from richtext.text id = "worlds" must go here on save(/worlds>
(objects>* //text from textarea.text id = "objets" must go here on save*(/objects>
(/root>
(had to use brackets otherwise they dont show)
AND THEN
When I open the saved file the text in the xml nodes must write back into the three components in the tabnavigator.
Please help, I am doing a course and my assignment is to write a desktop software and save all user input in xml and I am just not getting it.
Thanks for any help and patience
I think you need to keep the XML/Actionscript Object Serialization seperate from anything to do with saving the state of your application/document.
To keep things simple you could create a presentation Model for your three views to bind all the data from your views like so:
PresentationModel.as
[Bindable]
public var characters:String;
[Bindable]
public var worlds:String;
[Bindable]
public var objects:String;
Once you have all your data collected from your users input you could then either use Flex based serialization libraries to change value/complex object to XML or simply use the objects inside of a method to manually construct your XML file.

Making sure my extended lists always show "current" data?

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.

Grails - Removing an item from a hasMany association List on data bind?

Grails offers the ability to automatically create and bind domain objects to a hasMany List, as described in the grails user guide.
So, for example, if my domain object "Author" has a List of many "Book" objects, I could create and bind these using the following markup (from the user guide):
<g:textField name="books[0].title" value="the Stand" />
<g:textField name="books[1].title" value="the Shining" />
<g:textField name="books[2].title" value="Red Madder" />
In this case, if any of the books specified don't already exist, Grails will create them and set their titles appropriately. If there are already books in the specified indices, their titles will be updated and they will be saved. My question is: is there some easy way to tell Grails to remove one of those books from the 'books' association on data bind?
The most obvious way to do this would be to omit the form element that corresponds to the domain instance you want to delete; unfortunately, this does not work, as per the user guide:
Then Grails will automatically create
a new instance for you at the defined
position. If you "skipped" a few
elements in the middle ... Then Grails
will automatically create instances in
between.
I realize that a specific solution could be engineered as part of a command object, or as part of a particular controller- however, the need for this functionality appears repeatedly throughout my application, across multiple domain objects and for associations of many different types of objects. A general solution, therefore, would be ideal. Does anyone know if there is something like this included in Grails?
removeFrom*
Opposite of the addTo method in that it removes instances from an association.
Examples
def author = Author.findByName("Stephen King")
def book = author.books.find { it.title = 'The Stand' }
author.removeFromBooks(book)
Just ran into this issue myself. It's easy to solve. Grails uses java.util.Set to represent lists. You can just use the clear() method to wipe the data, and then add in the ones you want.
//clear all documents
bidRequest.documents.clear()
//add the selected ones back
params.documentId.each() {
def Document document = Document.get(it)
bidRequest.documents.add(document)
log.debug("in associateDocuments: added " + document)
};
//try to save the changes
if (!bidRequest.save(flush: true)) {
return error()
} else {
flash.message = "Successfully associated documents"
}
I bet you can do the same thing by using the "remove()" method in the case that you don't want to "clear()" all the data.
For a good explanation of deleting a collection of child objects with GORM have a look at the Deleting Children section of this blog post - GORM gotchas part 2
It's recommended reading, as are parts 1 and 3 of the series.
I am just starting to learn Grails myself and saw your question as an interesting research exercise for me. I do not think you can use the conventional data binding mechanism - as it fills in the blanks using some kind of Lazy map behind the scenes. So for you to achieve your goal your "save" method (or is it a function?) is unlikely to contain anything like:
def Book = new Book(params)
You need a mechanism to modify your controller's "save" method.
After some research, I understand you can modify your scaffolding template which is responsible for generating your controller code or runtime methods. You can get a copy of all the templates used by Grails by running "grails install-templates" and the template file you would need to modify is called "Controller.groovy".
So in theory, you could modify the "save" method for your whole application this way.
Great! You would think that all you need to do now is modify your save method in the template so that it iterates through the object entries (e.g. books) in the params map, saving and deleting as you go.
However, I think your required solution could still be quite problematic to achieve. My instinct tells me that there are many reasons why the mechanism you suggest is a bad idea.
For one reason, off the top of my head, imagine you had a paginated list of books. Could that mean your "save" could delete the entire database table except the currently visible page? Okay, let us say you manage to work out how many items are displayed on each page, what if the list was sorted so it was no longer in numerical order - what do you delete now?
Maybe multiple submit buttons in your form would be a better approach (e.g. save changes, add, delete). I have not tried this kind of thing in Grails but understand actionSubmit should help you achieve multiple submit buttons. I certainly used to do this kind of thing in Struts!
HTH
I'm just running into this same issue.
My application's domain is quite simple: it has Stub objects which have a hasMany relationship with Header objects. Since the Header objects have no life of their own, they're entirely managed by the Stub controller and views.
The domain class definitions:
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {headers lazy: false}
}
class Header {
String value
static belongsTo = Stub
}
I've tried the "clear and bind" method but the end result is that the "cleared" objects are left over in the database and grails will just create new instances for the ones that were not removed from the relationship. It does seem to work from an user's perspective, but it will leave lots of garbage objects in the database.
The code in the controller's update() method is:
stubInstance.headers.clear()
stubInstance.properties = params
An example: while editing the -many side of this relationship I have (for a given Stub with id=1):
<g:textField name="headers[0].value" value="zero" id=1 />
<g:textField name="headers[1].value" value="one" id=2 />
<g:textField name="headers[2].value" value="two" id=3 />
in the database there are 3 Header instances:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
after removing header "one" and saving the Stub object the database will have headers:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
id=4;value="zero"
id=5;value="two"
and the Stub object will now have an association with Headers with id=4 and id=5...
Furthermore, without the clearing of the list, if an index is not present in the submitted request.headers list, on data binding grails will keep the existing object at that location unchanged.
The solution that occurs to me is to bind the data, then check the Stub's headers for elements that are not present in the submitted list and remove them.
This looks like a pretty simple scenario, isn't there any built-in functionality to address it?
It's a bit overkill to have to write your own synchronization logic for maintaining relationships, especially when the quirks that make it non-trivial are caused by grails itself.
What about deletion, shouldn't the clear()'ed elements be gone from the database? Am I missing something in the relationship or domain object definitions?
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {
headers lazy: false
**headers cascade: "all-delete-orphan"**
}
}
class Header {
String value
static belongsTo = Stub
}
I have added the cascade property on the owning side of relationship and Now if you try to save the stub, it will take care of removing deleted items from the collection and delete them from the DataBase.

Resources