D365FO: SysTableLookup Fails if Value in Field - axapta

I am using custom lookup code on a form string control. It works great, unless there is any text in the field. Then, it always returns blank unless what is entered in the field is an exact match for a value in the list. My preference would be for the text in the field to serve as a startsWith filter (and already addressed when I make the value list), but at this point, I would be happy with even the full list appearing, instead of blanks.
public static client void lookupList(FormStringControl _formStringControl, List _valueList)
{
ListIterator valueIterator;
myLookupTempTable tempLookupTable;
SysTableLookup sysTableLookup;
if (_formStringControl && _valueList && _valueList.typeId() == Types::String)
{
valueIterator = new ListIterator (_valueList);
while (valueIterator.more())
{
tempLookupTable.Value = valueIterator.value();
tempLookupTable.insert();
valueIterator.next();
}
sysTableLookup = SysTableLookup::newParameters(tableNum(myLookupTempTable), _formStringControl);
sysTableLookup.addLookupfield(fieldNum(myLookupTempTable, Value), true);
sysTableLookup.parmTmpBuffer(tempLookupTable);
sysTableLookup.performFormLookup();
//dispose of the temp table
tempLookupTable = null;
}
}

Related

AX2009 update form field value

I want to auto-update the Format field of the NumberSequenceTable form. The purpose is to help the user while manually entering the data.
For example this field should preferably be updated with concatenated values of the fields Number sequence code and Largest.
After thinking for a while I decided to change the underlying table NumberSequenceTable. I changed its "modifiedField" method by adding another case to the already existing switch statement. I think this is the accepted best practice in such cases:
public void modifiedField(fieldId _fieldId)
{
#Define.DefaultCleanInterval(24)
#Define.DefaultCacheSize(10)
str sequenceFormat;
super(_fieldId);
switch (_fieldId)
{
....
//BEGINING
case fieldnum(NumberSequenceTable, NumberSequence):
if (this.NumberSequence && this.Highest && !this.Format)
{
sequenceFormat = System.Text.RegularExpressions.Regex::Replace(int2str(this.Highest), "[0-9]", "#");
this.Format = strFmt("%1_%2",this.NumberSequence, sequenceFormat);
}
break;
//END
default :
break;
}
}
My previous solution involved overriding the "enter" method on the form field. However this would not be in line with best practices. For information purposes I am pasting here the initial solution.
public void enter()
{
str sequenceNode;
str sequenceValue;
str maxValue;
str formatValue;
;
super();
//Get required fields value
sequenceNode = numberSequenceTable_ds.object(fieldnum(NumberSequenceTable,NumberSequence)).getValue();
maxValue = numberSequenceTable_ds.object(fieldnum(NumberSequenceTable,Highest)).getValue();
formatValue = numberSequenceTable_ds.object(fieldnum(NumberSequenceTable,Format)).getValue();
if(sequenceNode && maxValue && !formatValue) {
//Match regex pattern
maxValue = System.Text.RegularExpressions.Regex::Replace(maxValue, "[0-9]", "#");
sequenceValue = strFmt("%1_%2",sequenceNode,maxValue);
//Change field value
numberSequenceTable_ds.object(fieldnum(NumberSequenceTable,Format)).setValue(sequenceValue);
this.update();
}
}

How do you make a class method modify itself?

asp.net C#4
I have a simple class to working with query strings.
A new instance is created like this:
public QueryString(string querystring)
{
try
{
_table = new Hashtable();
if (querystring.Length > 0)
{
foreach (string pair in querystring.Split('&'))
{
string[] item = pair.Split('=');
_table.Add(item[0].ToLower(), item[1]);
}
}
}
catch (Exception)
{
}
}
I want to add a method to this that will remove a key value pair. I don't want it to return a new querystring, I just want it to remove the pair from the current instance. Not sure how to do that since it says I can't assign a value to 'this'
public void Remove(string key)
{
String querystring = this.ToString();
try
{
_table = new Hashtable();
if (key.Length > 0)
{
foreach (string pair in querystring.Split('&'))
{
string[] item = pair.Split('=');
if (item[0] != key)
{
_table.Add(item[0].ToLower(), item[1]);
}
}
this = _table;
}
}
catch (Exception)
{
}
}
You're overcomplicating things. Since your class's state is made up of the _table field, all you need to do is remove the item with the given key from that field.
The following example replaces your untyped Hashtable wit a strongly-typed Dictionary. I also chose to initialize the dictionary with a LINQ statement, but you could keep your old code there if you prefer.
public class QueryString
{
private readonly Dictionary<string, string> _table;
public QueryString(string querystring)
{
if (querystring.Length > 0)
{
var pairs =
from pair in querystring.Split('&')
let item = pair.Split('=')
select new {key = item[0], value = item[1]};
_table = pairs.ToDictionary(p => p.key, p => p.value);
}
}
public void Remove(string key)
{
_table.Remove(key);
}
}
You cannot assign a value to this since it is a reference to the object itself.
However, if you remove the line this = _table; , isn't things working as they should then? I guess your ToString() is somewhat using the hashtable to generate a "printer friendly" QueryString, and if that is the case, the way I see it, your Remove() method should be working (since you are replacing the _table variable with a new HashTable not including the key-value pair you want to exclude).
you are passing a querystring into the class so the original querystring IS intact.
However you then break down the querystring into a a Hashtable of key/value pairs. If you want to keep THAT intact you need to clone the HashTable and perform the remove on the clone.
In any case it's probably a good idea to keep the querystring you are passing in as a constructor parameter in a member variable for safe keeping.

Picking out Just JSON Data Returned from ASP.NET MVC3 controller Update

I've got data returned from my JavaScript client that just includes the data that has changed. That is, I may have an array with each row containing 10 columns of JSON downloaded, but on the Update, only the data that is returned to me is the data that got updated. On my update, I only want to update those columns that are changed (not all of them).
In other words, I have code like below but because I'm passing in an instance of the "President" class, I have no way of knowing what actually came in on the original JSON.
How can I just update what comes into my MVC3 update method and not all columns. That is, 8 of the columns may not come in and will be null in the "data" parameter passed in. I don't want to wipe out all my data because of that.
[HttpPost]
public JsonResult Update(President data)
{
bool success = false;
string message = "no record found";
if (data != null && data.Id > 0)
{
using (var db = new USPresidentsDb())
{
var rec = db.Presidents.FirstOrDefault(a => a.Id == data.Id);
rec.FirstName = data.FirstName;
db.SaveChanges();
success = true;
message = "Update method called successfully";
}
}
return Json(new
{
data,
success,
message
});
}
rec.FirstName = data.FirstName ?? rec.FirstName;
I would use reflection in this case because the code will be too messy like
if (data.FirstName != null)
rec.FirstName = data.FirstName
.
.
.
and so on for all the fields
Using reflection, it would be easier to do this. See this method
public static void CopyOnlyModifiedData<T>(T source, ref T destination)
{
foreach (var propertyInfo in source.GetType().GetProperties())
{
object value = propertyInfo.GetValue(source, null);
if (value!= null && !value.GetType().IsValueType)
{
destination.GetType().GetProperty(propertyInfo.Name, value.GetType()).SetValue(destination, value, null);
}
}
}
USAGE
CopyOnlyModifiedData<President>(data, ref rec);
Please mind that, this won't work for value type properties.

Flex combo box labelfunction

I have two questions regarding the Flex combo box.
The string representing the function name will be read from xml # run time.
var combo:ComboBox = new ComboBox();
combo.labelFunction = "functionName";
How can I achieve this?
So the first name, which is to be displayed in the combo box, can be only retrieved by accessing another DTO, called person and then its first name.
var combo:ComboBox = new ComboBox();
combo.labelField= "person.firstName";
My class looks like this,
public class Test
{
public var person:PersonDTO;
}
public class PersonDTO
{
public var firstName:String;
}
Is it possible to access any multi-level text using the combo box label field ?
You need to pass the function not the name.
Doing this
combo.labelFunction = "functionName";
Is passing a string.
The only work around I can think of is to make a switch statement with one case for each function you may have. Then call that with "case" from within your xml.
switch( xml.#labelfunction ){
case 'func1':
combo.labelFunction = this.func1;
break;
case 'func2':
combo.labelFunction = this.func2;
break;
}
Its hacky but should work.
ad 1) labelFunction
Calling functions when you know only the name as String is quite easy. The following snippets shows how you can execute a function that is a member of the same class. In case you need to call a function from another class replace this with the according variable name.
private function comboBox_labelFunction(item:Object):String
{
var functionName:String = myXml.#labelFunctionName;
return this[functionName](item);
}
ad 2) labelField
It's normally not possible to use "person.firstName" as labelField. However, you should be able use it within your labelFunction. Something like this should work...
private function comboBox_labelFunction(item:Object):String
{
var labelField:String = "person.firstName";
var attributeNames:Array = labelField.split(".");
for each (var attributeName:String in attributeNames)
{
if (item && item.hasOwnProperty(attributeName))
item = item[attributeName];
else
return null;
}
return item;
}

ASP.Net Custom Control

I am developing a custom control that needs to display a dropdownlist as a composite control.
The drop down list gets populated from a Rest web service. The problem I am facing is that the dropdownlist only has DataTextField and DataValueField but I need a way of storing more values in the control i.e. I have a couple of other properties I need to access for the selected item.
What is the best way of going about this?
Here is the code I have so far:
[ValidationProperty("SelectedValue")]
public class SelectSurveyControl : Panel
{
private DropDownList ddlSurveys;
public string SelectedSurveyId
{
get
{
return SelectedValue;
}
}
public string SelectedSurveyJavascriptEmbedCode
{
get
{
return this.ddlSurveys.SelectedItem.Attributes[""];
}
}
public string SelectedValue
{
get
{
return ddlSurveys.SelectedValue;
}
set
{
if (ddlSurveys == null)
{
ddlSurveys = new DropDownList();
}
ddlSurveys.SelectedValue = value;
}
}
protected override void OnLoad(EventArgs e)
{
base.OnInit(e);
if (ddlSurveys == null)
{
ddlSurveys = new DropDownList();
}
IList<Survey> surveys = GetSurveys();
this.ddlSurveys.DataSource = surveys;
this.ddlSurveys.DataTextField = "title";
this.ddlSurveys.DataValueField = "id";
this.ddlSurveys.DataBind();
ddlSurveys.SelectedValue = this.SelectedValue;
ddlSurveys.CssClass = "umbEditorTextFieldMultiple charlimit";
ddlSurveys.Attributes.Add("SurveyId", SelectedSurveyId);
ddlSurveys.Attributes.Add("JavascriptEmbedingCode", SelectedSurveyId);
this.Controls.Add(ddlSurveys);
}
public IList<Survey> GetSurveys()
{
...
}
}
Try using a string join/split to store and retrieve the various values, then you don't have to customize your dropdown list very much.
For Example:
Text: Some Title
Value: 1|testing test|2/12/2010
This will let you store as many values as you want, so long as you choose an appropriate character to join and split on. I usually use the bar, as in my example above.
Side Note: I was looking at your selected value set handler and it needs some tweaking. You shouldn't check for a null drop down list, instead you should call EnsureChildControls() before each get and set instead. Make sure you override the CreateChildControls() method and create your controls there.
You could use a hidden field and iterate thru a copy of the returned Surveys like this:
foreach(Survey s in Surveys){
string val = s.id + ":" + s.<property1> + ":" + s.<property2>;
hiddenField.Value += val +",";
}
When you need to read from the hidden field, you use String.Split to separate the values into arrays using ',' as the separator and in each array, you split again using ':'.
In the first split Array1[0] who be the survey id and Array1[n!=0] would be the properties of the Survey with the id = Array1[0]. Array[n!=0] would then be split into Array2.
I would suggest handling empty property values with an empty string or something or else you might end up with unequal lengths especially if you specify StringSplitOptions.RemoveEmptyEntries.
Agricfowl

Resources