I'm writing a GUI extension and using the Anquilla framework to get a list of Keywords within a Category. I'm obtaining an XML document for the list of keywords then working with that document within my extension.
My problem is that the returned XML doesn't contain the Keyword's 'Description' value. I have the Title and Key etc.
My original code looks like this:
var category = $models.getItem("CATEGORYTCMID:);
var list = category.getListKeywords();
list.getXml();
A typical node returned is this:
<tcm:Item ID="tcm:4-1749-1024"
Type="1024" Title="rate_one" Lock="0" IsRoot="true"
Modified="2012-12-17T23:01:59" FromPub="010 Schema"
Key="rate_one_value" IsAbstract="false"
CategoryTitle="TagSelector"
CategoryID="tcm:4-469-512" Icon="T1024L0P0"
Allow="268560384" Deny="96" IsNew="false"
Managed="1024"/></tcm:ListKeywords>
So I've tried using a Filter to give me additional column information:
var filter = new Tridion.ContentManager.ListFilter();
filter.columns = Tridion.Constants.ColumnFilter.EXTENDED;
var list = category.getListKeywords(filter);
Unfortunately this only gives the additional XML attributes:
IsShared="true" IsLocalized="false"
I'd really like the description value to be part of this XML without having to create a Keyword object from the XML. Is such a thing possible?
cough any ideas? cough
I'm afraid you'll have to load the Keyword itself to get the Description.
It's not used in any lists, so it's not returned in the XML.
You could always create a List Extender to add this information to the list, but try to be smart about it since this extender will execute everytime a GetList is called.
Won't save you from having to open every keyword in the list, but you'll be doing it server-side (with Core Service/NetTcp for instance) which will probably be easier and faster than opening each keyword with Anguilla.
In this instance I only need the one keyword, so I simply get it from the CMS. Getting an object in Anguilla is a bit weird, here's the code:
In your main code area:
var selectedKy = $models.getItem("TcmUriOfKeywordHere");
if (selectedKy.isLoaded()) {
p.selectedKy = selectedKy;
this.onselectedKyLoaded();
} else {
$evt.addEventHandler(selectedKy, "load", this.onselectedKyLoaded);
selectedKy.load();
}
It's worth noting how I store the keyword in the properties of the item, so I can obtain it in the onselectedKyLoaded function
The function called once the item is loaded
ContentBloom.ExampleGuiExtension.prototype.onselectedKyLoaded = function (event) {
var p = this.properties;
var selectedDescription = p.selectedKy.getDescription();
// do what you need to do with the description :)
};
I resolved this, thanks to the answer here: https://stackoverflow.com/a/12805939/1221032 - Cheers Nuno :)
Related
From time to time I have the requirement to bind a control property to based on data out of model A to another model B.
For example the syntax could look like this (but will not work):
text : "{B>/rootB/{A>someValue}/propertyB}"
I normally solve this problem by "misusing" an unused control property in combination with the format function. It would look like this:
tooltip : {
path : "A>someValue",
formatter : function(oValue) {
// do some checks on oValue
var path = "B>/rootB/"+oValue+"/propertyB";
this.bindProperty("text", path);
return undefined; // because tooltip is not used
}
The benefit of this, each time "A>someValue" will be changed the binding of "text" will be updated automatically.
It is also possible to do this in template code (like items aggregations).
But you may smell the code ;)
Any suggestions to make it cleaner?
As far as I know, there is no such possibility in UI5 (yet). I always use a formatter function as you already mentioned. I say not YET, because developers seem to be aware of this feature request: see on GitHub
BUT, you dont need to missuse a random control property! Just use the formatter to read the needed values from any model you have access to:
text : {
path : "A>someValue1",
formatter : function(oValue) {
// read model B to get someValue2 (based on someValue1)
var path = "B>/rootB/"+oValue+"/propertyB";
var B = getModel("someModel");
var someValue2 = B.getProperty(path);
return someValue2
}
function IfModuleSucceded(sender, args) {
var existingCount = existingItems.get_count();
var existEnumerator = existingItems.getEnumerator();
while (existEnumerator.moveNext()) {
var currentmodule = existEnumerator.get_current();
var URL = currentmodule.get_item("Request_URL");
alert(URL);
}
}
In this Code i am trying to Retrieve the url of a Hyperlink column which is in a SharePoint list, using Client object model, but i have received an object. How could i get the Url out of this received object ????
when this code is executed, it gives the alert as "[Object Object]".
would anyone help me to sort this out ??
The answer will be alert(url.url) as it's an object.
It will also have a property called description
The Hyperlink field has two properties: Description and Url.
You can access the properties like this: ObjectName.PropertyName
So for your URL object in your example, you can reach the properties like this: URL.Url and URL.Description
I found that Url and Description are case sensitive, so make sure you capitalize where necessary.
This worked great for me.
Afternoon,
I am getting the following error, and cant work out why... Can some one please take a look and let me know where i am going wrong.
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
below is what i am trying to use, to get a list back so i can use it with Amazon. I have tried to remove the .ToList() bit but nothing seems to work. I am calling an MS SQL view "GetASINForUpdateLowPrices" which returns a list back of product ASIN's
List<string> prodASINs = dc.GetASINForUpdateLowPrices.ToList();
SQL for the view i am using, this may help a little bit more.
SELECT asin
FROM dbo.aboProducts
WHERE (asin NOT IN
(SELECT aboProducts_1.asin
FROM dbo.aboProducts AS aboProducts_1 INNER JOIN
dbo.LowestPrices ON aboProducts_1.asin = dbo.LowestPrices.productAsin
WHERE (dbo.LowestPrices.priceDate >= DATEADD(day, - 1, GETDATE()))))
What data type is a single ASIN?
Probably your GetASINForUpdateLowPrices is not an IEnumerable<string>. Try this to confirm:
List<string> prodASINs = dc.GetASINForUpdateLowPrices
.Select(e => e.ToString())
.ToList();
When you call your GetASINForUpdateLowPrices, it wont directly return List<string> even if there is only one field in your view. Try the following approach:
List<string> prodASINs = dc.GetASINForUpdateLowPrices
.Select(item => item.AsinFieldName)
.ToList();
Visual Studio IntelliSense should suggest you the property name after typing item.. If the property is not string try to add .ToString() at the end of the property name.
Edit: After your comment, it seems like you need to use it as .Select(item => item.asin.ToString()).
Just use var.
var prodASINs = dc.GetASINForUpdateLowPrices.ToList();
Are you sure that GetASINForUpdateLowPrices.ToList() creates a List of Strings? My best estimation is that it is a generic list of a different type.
To figure out what is going on - Change List<string> prodASINS to be Object obj. Then set a breakpoint to see what List type is actually generated by your ToList() code by checking out the object using the debugger. You can then update your code to move the values into a list of the appropriate type.
You might have to cast the right side of the assignor like this to ultimately get the job done (replacing string with another type if necessary) - List<string> prodASINs =(List<string>)dc.GetASINForUpdateLowPrices.ToList()
Following on from my earlier question about creating Address Books (many thanks Peter!), I have a small throw-away console application doing just that and working great - but in addition I'm trying to update the metadata of a Keyword with the Item Id of the created Address Book.
Slightly shortened snippet ...
StaticAddressBook ab = new StaticAddressBook();
ab.Title = title;
ab.Key = key;
ab.Save();
// id is a correct Keyword TCM ID
Keyword k = tdse.GetObject(id, EnumOpenMode.OpenModeEdit);
if (k != null)
{
k.MetadataFields["addressbookid"].value[0] = ab.Id.ItemId;
k.Save(true);
}
I keep getting the following error on Save():
XML validation error. Reason: The element 'Metadata' in namespace
'uuid:2065d525-a365-4b45-b68e-bf45f0fba188' has invalid child element
'addressbookid' in namespace
'uuid:2065d525-a365-4b45-b68e-bf45f0fba188'. List of possible elements
expected: 'contact_us_email' in namespace
'uuid:2065d525-a365-4b45-b68e-bf45f0fba188'
But I know the Keyword has the correct Metadata assigned, (thats why I don't bother checking!). Shortened Tridion XML from a current keyword in question:
<tcm:Keyword>
<tcm:Data>
<tcm:MetadataSchemaxlink:type="simple"xlink:title="IP.Location.Metadata" xlink:href="tcm:49-2142-8" />
<tcm:Metadata>
<Metadata xmlns="uuid:2065d525-a365-4b45-b68e-bf45f0fba188">
<email>...</email>
<addressbookid>3</addressbookid>
<contact_us_email>...</contact_us_email>
<request_a_sample_email>...</request_a_sample_email>
<webinar_feedback_email>....</webinar_feedback_email>
</Metadata>
</tcm:Metadata>
<tcm:IsRoot>true</tcm:IsRoot>
</tcm:Data>
</tcm:Keyword>
Have I missed something can Keyword metadata not be updated in this way?
I guess I could look at the Core Service to update Keywords, but it seemed to to make sense to do everything within this application.
UPDATE
Order was key here, strangely!
The following code works:
ItemFields fields = k.MetadataFields;
System.Diagnostics.Debug.WriteLine(fields.Count);
string email = fields[1].value[1];
string contact = fields[3].value[1];
string request = fields[4].value[1];
string webinar = fields[5].value[1];
fields[1].value[1] = email;
fields[2].value[1] = ab.Id.ItemId;
fields[3].value[1] = contact;
fields[4].value[1] = request;
fields[5].value[1] = webinar;
k.Save(true);
Got caught out by the non-0-based index when getting/setting values and had to reassign existing fields back, in order.
Cheers
It seems that the order of the fields has changed in the Schema since that Component was created. At least the Schema expects contact_us_email in the position where you current have addressbookid.
There may be other changes, so I'd verify the order of fields in the Schema and make sure the Component(s) match, before you run your tool.
I have a script that parses some complex XML. When the XML element is of a certain type, it generates a comboBox using the XML element's children to populate the box. I then want to check all of the values of the all the generated ComboBoxes against their correct answers (which is also info stored in the XML file). When creating the ComboBoxes, I added an "id" property. However, it seems that I cannot them use:
dynamicQuestion.id.selectedItem.labelField
to check the answers. However, I am able to get the labelField if I know the variable name used to create the ComboBox.
dynamicQuestion.selectedItem.labelField
This indicates (to me) that I need to dynamically generate the variable name as I'm creating new instances of the ComboBox. But how do I dynamically generate a variable name? If I use
var thisBox:String = "box"+boxCount;
var newBox:ComboBox = thisBox as ComboBox;
I get an implicit coercion error. I also tried changing the creation statement to a function that accepted an argument, "thisBox," but this didn't work either. Conceptually, this seems quite simple, but I'm having a hard time putting it to practice. It seems that the comboBox's id is what is generated by created the box using script (e.g., var thisBox). How do I dynamically generate this name?
Use an array as Stefan suggested. If you must use string identifiers, you can create an object and use it as an associative array.
var combos:Object = {};
var boxCount:Number = 1;
var thisBox:String = "box"+boxCount;
//you can store comboboxes in the object using the following syntax
combos[thisBox] = new ComboBox();
//or
combos.box2 = new ComboBox();
//or
combos["box3"] = new ComboBox();
trace(combos.box1.selectedItem.labelField);
trace(combos.box2.selectedItem.labelField);
trace(combos.box3.selectedItem.labelField);
Why don't you store all your dynamically created combo boxes in an array? When you want to evaluate them you iterate over the array and access selectedItem.labelField.