Best way of dynamically binding xpages field values to backend document - xpages

I am having a form with multiple fields like "Persp_1", "Persp_2", "Persp_3"...., Goal_1, Goal_2, Goal_3.... etc. Currently I am assigning the values from the xPage component to the backend document via a common function as belows:
function pushDataToBackEnd(sourceDoc:NotesDocument, fieldArray){
try{
for(var i=0; i<fieldArray.length;i++){
for(var j=0; j<12; j++){
a = j+1;
var fieldName = fieldArray[i] + "_" + a;
var fieldValue = getComponent(fieldName).getValue();
if(fieldValue != ""){
sourceDoc.replaceItemValue(fieldName,fieldValue);
}
}
}
return true;
}
catch(exp){
return exp
}
return true;
}
The problem is I also need to bind the components of the xPage with the backend fields on the notes form. Is there a way in which I can do this.

Use a custom control and a repeat control to dynamic bind fields. With the backend data.
Check out this post
Dynamic Data Binding?

Related

j2me - Does a List have any property to keep track of 'key' that identify the item

How do you usually deal with Lists and the fact that they don't have a property to clearly identity an specific item ?
So far, the only solucion I could come up with is to put the key I use at the beginning, followed by a hyphen and the text that is shown on every item.
This way when I retrieve the text from the selected item I can get the key for the item.
This is how I do it, but surely there's gotta be a better solution and I'd really like that you could share your experience in this kind of scenarios.
Thanks in advance.
The picture ooks like you keep all the data managed in your application inside the text of the items of a standard list.
Better hava a separate class for the data container objects and an overview screen derived from List that takes an array of those container objects and instantiate the Items from that. This screen could then provide a method
DataContainer getSelectedObject()
which uses getSelectedIndex() internally to look up the object.
More specifically (Overview.java)
package mvc.midlet;
import javax.microedition.lcdui.List;
public class Overview extends List {
private final DomainObject[] data;
public static Overview create(DomainObject[] data) {
int i = 0;
for(; i < data.length; i++) {
if(data[i] == null) break;
}
String[] names = new String[i];
for(int j = 0; j < i; j++) {
names[j] = data[j].name;
}
return new Overview(names, data);
}
protected Overview(String names[], DomainObject[] data) {
super("Overview", IMPLICIT, names, null);
this.data = data;
}
public DomainObject getSelectedObject() {
return data[this.getSelectedIndex()];
}
}

Getting ViewPanel Headers programmatically

This code does provide me the values I am wanting in my comboBox, but I am wondering if there is a way to get the viewColumn ID, viewColumnHeader ID, and number of columns in the viewPanel programmatically. The viewPanel is using a JDBCQuery as the datasource.
var itemList:java.util.Vector = new java.util.Vector;
var colID = "viewColumn"; //default id assigned
var colHeaderID = "viewColumnHeader"; //default id assigned
var end = 10; //max # of viewPanel columns
itemList.add("Select Column");
for(x=1;x<end;x++) {
try {
if(getComponent(colID + x) == null) {
throw ("Only " + (x-1) + " columns in ViewPanel");
x=end;
} else {
var disColID = getComponent(colID + x).getColumnName();
}
var disColHeaderID = getComponent(colHeaderID + x).getValue();
itemList.add(disColHeaderID + "|" + disColID);
} catch (e) {
dBar.info(e.toString());
}
}
itemList
The current way is obviously restricted to only 9 columns and ensuring the viewColumn ID and viewColumnHeader ID have a specific naming structure which would be nice to get away from.
All the columns of a view panel can be accessed by getting the child components of view panel using viewPanelObj.getChildren(). The column headers are a part of view column and after you get the handle of view column you can access the header using viewColumnObj.getHeader().
So a sample SSJS code to access all the view columns and view headers would look something like this:
var viewPnl:com.ibm.xsp.component.xp.XspViewPanel = getComponent("viewPanel1");
var list:java.util.List = viewPnl.getChildren();
for (var i=0 ; i<list.size() ; i++) {
var viewCol:com.ibm.xsp.component.xp.XspViewColumn = list.get(i);
var viewHdr:com.ibm.xsp.component.xp.XspViewColumnHeader = viewCol.getHeader();
// Perform required operations on objects of viewCol & viewHdr
}

Dynamics CRM - Accessing Custom Product Option Value

Is there a way to programmatically access the Label & Value fields that has been created as a custom Field in MS CRM Dynamics please?
I have added a custom field called "new_producttypesubcode" which, for example, has 2 options, Trophy = 1000000 and Kit = 10000001.
I am writing an import utility that mirrors products between the customers website and their CRM and I want to get a list of all possible product options in the CRM to see if they are matched in the website.
So, in essence I want to...
get the list of possible new_producttypesubcodes and their corresponding values.
Iterate through the product variants in the website.
if the product variant name matches any name in the list of new_producttypecodes then add the value 1000000
So, if I find a product added to the website and its marked as a "Trophy" and "Trophy" exists in the CRM then new OptionSetValue(100000001)
I hope that makes sense...
Thanks
This function retrieves a dictionary of possible values localised to the current user. Taken from: CRM 2011 Programatically Finding the Values of Picklists, Optionsets, Statecode, Statuscode and Boolean (Two Options).
static Dictionary<String, int> GetNumericValues(IOrganizationService service, String entity, String attribute)
{
RetrieveAttributeRequest request = new RetrieveAttributeRequest
{
EntityLogicalName = entity,
LogicalName = attribute,
RetrieveAsIfPublished = true
};
RetrieveAttributeResponse response = (RetrieveAttributeResponse)service.Execute(request);
switch (response.AttributeMetadata.AttributeType)
{
case AttributeTypeCode.Picklist:
case AttributeTypeCode.State:
case AttributeTypeCode.Status:
return ((EnumAttributeMetadata)response.AttributeMetadata).OptionSet.Options
.ToDictionary(key => key.Label.UserLocalizedLabel.Label, option => option.Value.Value);
case AttributeTypeCode.Boolean:
Dictionary<String, int> values = new Dictionary<String, int>();
BooleanOptionSetMetadata metaData = ((BooleanAttributeMetadata)response.AttributeMetadata).OptionSet;
values[metaData.TrueOption.Label.UserLocalizedLabel.Label] = metaData.TrueOption.Value.Value;
values[metaData.FalseOption.Label.UserLocalizedLabel.Label] = metaData.FalseOption.Value.Value;
return values;
default:
throw new ArgumentOutOfRangeException();
}
}
So you would then need to do something like:
Dictionary<String, int> values = GetNumericValues(proxy, "your_entity", "new_producttypesubcode");
if(values.ContainsKey("Trophy"))
{
//Do something with the value
OptionSetValue optionSetValue = values["Trophy"];
int value = optionSetValue.Value;
}
Yes, that data is all stored in the metadata for an attribute (SDK article). You have to retrieve the entity metadata for the entity and then find the attribute in the list. Then cast that attribute to a PicklistAttributeMetadata object and it will contain a list of options. I would mention that typically retrieving Metadata from CRM is an expensive operation, so think about caching.
private static OptionSetMetadata RetrieveOptionSet(IOrganizationService orgService,
string entityName, string attributeName)
{
var entityResponse = (RetrieveEntityResponse)orgService.Execute(
new RetrieveEntityRequest
{ LogicalName = entityName, EntityFilters = EntityFilters.Attributes });
var entityMetadata = entityResponse.EntityMetadata;
for (int i = 0; i < entityMetadata.Attributes.Length; i++)
{
if (attributeName.Equals(entityMetadata.Attributes[i].LogicalName))
{
if (entityMetadata.Attributes[i].AttributeType.Value ==
AttributeTypeCode.Picklist)
{
var attributeMD = (PicklistAttributeMetadata)
entityMetadata.Attributes[i];
return attributeMD.OptionSet;
}
}
}
return null;
}
Here is how to write the options to the console using the above call.
var optionSetMD = RetrieveOptionSet(orgService, "account", "accountcategorycode");
var options = optionSetMD.Options;
for (int i = 0; i < options.Count; i++)
{
Console.WriteLine("Local Label: {0}. Value: {1}",
options[i].Label.UserLocalizedLabel.Label,
options[i].Value.HasValue ? options[i].Value.Value.ToString() : "null");
}
I believe this works for global option set attributes as well, but if you know it is a global option set there is a different message for it that would probably a bit more efficient (SDK article).

cloning/copying a dojo data store

Hi can some one please tell me how to copy one data store to another in dojo. I tried it in following way but it doesn't work. Here I'm try to copy data from jsonStore to newGridStore.
jsonStore.fetch({query:{} , onComplete: onComplete});
var onComplete = function (items, request) {
newGridStore = null;
newGridStore = new dojo.data.ItemFileWriteStore({
data : {}
});
if (items && items.length > 0) {
var i;
for (i = 0; i < items.length; i++) {
var item = items[i];
var attributes = jsonStore.getAttributes(item);
if (attributes && attributes.length > 0) {
var j;
for (j = 0; j < attributes.length; j++) {
var newItem = {};
var values = jsonStore.getValues(item, attributes[j]);
if (values) {
if (values.length > 1) {
// Create a copy.
newItem[attributes[j]] = values.slice(0, values.length);
} else {
newItem[attributes[j]] = values[0];
}
}
}
newGridStore.newItem(newItem);
}
}
}
}
Based on the comments asked above. You are trying to copy values to a new Store for the single reason to be able to detect which values have changes and then save them individually, without having to send the entire store.
This approach is totally wrong.
Dojo has isDirty() and offers you the ability to revert() a store back to it's original values. It knows which values have changed and you don't need to do this.
Take a look at the bog standard IFWS here: http://docs.dojocampus.org/dojo/data/ItemFileWriteStore
Make sure you read everything from here: http://docs.dojocampus.org/dojo/data/ItemFileWriteStore#id8
What you want to do is create your own _saveCustom method which you will override your store with, and then when you save, you will be able to see which values have changed.
Click on the demo at the very bottom of the page. It shows you EXACTLY how do to it using _saveCustom

adding a js method

I have a js function that is named getID which is basically return document.getElementById(id)
I want to make another function, getTag that would return getElementsByTagName.
The part that I can't seem to manage is that I want to be able to call them like this:
getID('myid').getTag('input') => so this would return all the input elements inside the element with the id myid
Thanks!
ps: getTag would also have to work if it's called by it's own, but then it would just return document.getElementsByTagName
UPDATE:
Thanks to all that have replied! Using your suggestions I came up with this, which works well for me:
function getEl(){
return new getElement();
}
function getElement() {
var scope = document;
this.by = function(data){
if (data.id) scope = scope.getElementById(data.id);
if (data.tag) scope = scope.getElementsByTagName(data.tag);
return scope;
}
}
and I use it like this:
var inputs = getEl().by({id:"msg", tag:"input"});
The way to do that is to prototype Object. To do that, you'll need the following piece of code:
Object.prototype.getTag = function(tagName) {
return this.getElementsByTagName(tagName);
}
However, this will expand all objects because what you really need to prototype, an HTMLElement, is very hard to do consistently. All the experts agree that you should never expand the Object prototype. A much better solution would be to create a function that gets the tag name from another argument:
function getTag(tagName, element) {
return (element || document).getElementsByTagName(tagName);
}
// Usage
var oneTag = getTag('input', getID('myid')); // All inputs tags from within the myid element
var twoTag = getTag('input'); // All inputs on the page
This would require that whatever is returned by getID('myid') (an HTML element) exposes a method named getTag(). This is not the case. Browsers implement the DOM specification and expose the methods defined there.
While you technically can enhance native objects with your own methods, it's best not to do it.
What you try to do has been solved rather nicely in JS libraries like jQuery already, I recommend you look at one of them before you invest time in mimicking what they can do. For example, your line of code would become:
$("#myid input")
in jQuery. jQuery happens to be the most widely used JS library around, there are many others.
Basically, you're going to create a single object that contains each of your methods and also stores all data returned by the native functions. It would look something like this (not tested, but you get the idea):
var MyLib = {
getID: function(id) {
var element = document.getElementById(id);
this.length = 1;
this[0] = element;
return this;
},
getTag: function(tag) {
var elements;
if (this.length) {
for (var i = 0; i < this.length; i++) {
var byTag = this[i].getElementsByTagName(tag);
for (var j = 0; j < byTag.length; j++) {
elements.push(byTag[j]);
}
}
}
for (var i = 0; i < elements.length; i++) {
this[i] = elements[i];
}
this.length = elements.length;
return this;
}
};
You can then use it like this:
var elements = MyLib.getID('myid').getTag('input');
for (var i = 0; i < elements.length; i++)
console.log(elements[i]); // Do something
The only real problem with this approach (besides it being very tricky and hard to debug) is that you have to treat the result of every method like an array, even if there is only a single result. For example, to get an element by ID, you'd have to do MyLib.getID('myid')[0].
However, note that this has already been done before. I recommend you take a look at jQuery, if only to see how they accomplished this. Your code could be simplified to this:
$("#myid input")
jQuery is more lightweight than you think, and including it on your page will not slow it down. You have nothing to lose by using it.
Just use the DOMElement.prototype property.
You'll get something like this :
function getTag(tagName) {
return document.getElementsByTagName(tagName);
}
DOMElement.prototype.getTag = function(tagName) {
return this.getElementsByTagName(tagName);
}
But you should use jQuery for this.
EDIT: My solution doesn't work on IE, sorry !
You could define it as follows:
var Result = function(el)
{
this.Element = el;
};
Result.prototype.getTag = function(tagName)
{
return this.Element.getElementsByTagName(tagName);
};
var getTag = function(tagName)
{
return document.getElementsByTagName(tagName);
};
var getID = function(id)
{
var el = document.getElementById(id);
return new Result(el);
};
Whereby a call to getID will return an instance of Result, you can then use its Element property to access the HTML element returned. The Result object has a method called getTag which will return all child elements matching that tag from the parent result. We then also define a seperate getTag method which calls the document element's getElementsByTagName.
Still though...JQuery is so much easier... $("#myId input");
Unless this is an academic exercise on how to chain methods in JavaScript (it doesn't seem to be, you simply seem to be learning JavaScript), all you have to do is this:
var elements = document.getElementById("someIdName");
var elementsByTag = elements.getElementsByTagName("someTagName");
for (i=0; i< elementsByTag.length; i++) {
alert('found an element');
}
If you want to define a reusable function all you have to do is this:
function myFunction(idName,tagName) {
var elements = document.getElementById(idName);
var elementsByTag = elements.getElementsByTagName(tagName);
for (i=0; i< elementsByTag.length; i++) {
alert('found a ' + tagName + ' element within element of id ' + idName);
}
}
It's true that if this is all the JavaScript functionality you need on your page, then there is no need to import jQuery.

Resources