I want to program with the Method super() in Dynamics AX2012.
I have build a class ("A") and some methods in it. I build another class("B") whhich extends from the class before.
My class "A" has some Methods.
Now in Class "B" I want to override a Method. I will do so.
I will override the Method getTable().
protected SYCCarBrandTable getTable()
{
SYCCarBrandTable ret;
ret = super();
{
select brandid,branddescription from ret
where ret.brandid == "Bentley";
}
return ret;
}
Now my Question is...
I have understood that with super() this new method did take everything with it, from the method which it Extended from in the motherclass "A".
But how can I add more Things to the method, so that it gives me the Things from the method before and the Things I have added in the overriden method ?
Looking at the implementation of getTable(), looks like you may want to select some SYCCarBrandTable record using the values of another SYCCarBrandTable returned by super() as criteria + other newly added criteria.
I am not sure why you would like to do such a thing, but if you perform the select statement upon the same table variable, you are actually really overriding all behavior, not adding anything.
If I got it right, you may want to use another SYCCarBrandTable:
protected SYCCarBrandTable getTable()
{
SYCCarBrandTable superCar;
SYCCarBrandTable ret;
superCar = super();
select brandid,branddescription from ret
where ret.CriteriaA = superCar.CriteriaA
&& ret.brandid == "Bentley";
return ret;
}
Then again, I am not sure why such a thing would be useful, but this is one sample way of aggregating functionality instead of fully overriding it.
If you want to add additional critria to a select you should use query object and design your select. Than you should create a new method on your base class called something like modifieQuery() or setQueryRange(). In this method you add range to your query as you want for base class. When you override this method in your class "B" you call super and than add additional ranges or simply override method without super() and just set ranges as needed. In your getTable method on base class you call modifieQuery() and execute it.
Related
I've created a simple form with an enum field on a grid, dragged from the DataSource CompanyImage:
Table CompanyImage has an Index on this field named Brand in my example and AllowDuplicates is set to No :
And here is the form:
I've overridden the close() method of the form like this:
public void close()
{
CompanyImage_ds.write();
super();
}
An error is displayed when I close it saying that
"Cannot create a record in CompanyImage(CompanyImage). Legal entities: Example1.
The record already exists."
That's fine but I would like a way to stop closing the window when this happens. A validateWrite() would be nice but I am not really able to figure out where and what to write in order to accomplish this behavior.
I mean, how to check that new row is added and it contains a field that already exists in the table ?
You shouldn't have to force the write() method. Closing the form should already do it.
If you wish to check something to allow the form to be closed, the close() method is too late in execution. You should leverage the canClose() method.
You could override the validate method of the grid column. You would need to write some validation logic in that method but that would prevent the column from saving at all if validation failed.
public boolean validate()
{
boolean ret;
// write your own validation logic
if (validation logic is true)
{
ret = true;
}
return ret;
}
I have a query-based report in which the query has some interactive ranges enabled on them. This is great except the value is blank, or has the last values used pre-populated. One of these is Vendor account number. If I wanted to have this report to pre-populate the Vend account based on whichever Vendor account record is selected (the caller), how would I be able to achieve this?
The answer was easy, although hard to find. I wasn't aware that you could access query objects from within a controller. The solution is to create a Controller class with only a main() method defined as normal, and the prePromptModifyContract method overridden. The following code will solve the problem:
SomeTable someTable;
Query query;
super();
if (this.parmArgs() && this.parmArgs().dataset() == tableNum(SomeTable))
{
someTable = this.parmArgs().record();
query = this.getFirstQuery();
SysQuery::findOrCreateRange(query.dataSourceTable(tableNum(SomeOtherTable)), fieldNum(SomeOtherTable, SomeOtherField)).value(SysQuery::value(someTable.SomeField));
}
I haven't tried this, but you could override the query's init method and call to element.args().record() as in a Form.
Something like this:
public void init()
{
VendTable vendTable;
super();
if (element.args().dataset() == tableNum(VendTable))
{
vendTable = element.args().record();
//populate your ranges with vendTable
}
}
I hope it works!
Sometimes, when I need to do more complicated stuff than change one value in datasource, I would like some method on caller. For example I have a form A with overview. Form A has method setName() (I define). I open a related detail (form B). I change something and I want to call setName on caller.
Nowdays I am doing it in following way
element.args().caller().setName();
but I am looking for more idiomatic way. So what is proper way of calling method on caller in AX 2012 R3?
It sounds like you need to change your development methodology if you referencing that many caller-form methods. You would mostly do that for calling doRefresh or calling updateDesign, which are both typically created methods on forms. Beyond updating the design and refeshing, you should use a class form handler.
If you must do a caller-callback, you can validate by doing:
if (formHasMethod(element.args().caller(), identifierstr(updateDesign)))
{
element.args().caller().updateDesign();
}
You can pass your class as the caller. Here is a simple sample set of code:
\Forms\Form1\Designs\Design\[Group:Group]\Button:Button\Methods\clicked:
void clicked()
{
FormRun formRun;
Args args = new Args(formstr(Form2));
TestClass testLocal = new TestClass();
testLocal.parmTestVar('ZZZ');
args.caller(testLocal);
formRun = classfactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.wait(true);
}
\Forms\Form2\Methods\init:
public void init()
{
TestClass testClass;
super();
testClass = element.args().caller() as testClass;
info(strFmt("%1", testClass.parmTestVar()));
}
Look at \Forms\SalesTable and \Classes\SalesTableForm or \Classes\SysCompare\startCompareOfContextProvider and the init method
identifierStr is not depreciated. It's a normal intrinsic function, but you will get a best practice warning if you use the identifierStr function. This is because no existence checking is carried out for identifierStr. Try to use a more specific intrinsic function if one is available. See http://msdn.microsoft.com/en-us/library/aa626893.aspx
You could take a look at Calling methods on a caller form, but identifierStr is deprecated in AX 2012. As far as I know there is no way to check for form methods at compile time.
But I would suggest avoiding methods on forms. Place them in a form handler class instead, you can then use the methodStr function to check for a method.
I am having a little play with Flex and I'm curious as to a few things.
Firstly for my instance variables I can define something like
private var _count:int = 0;
It then seems that If I have a getter and setter for count e.g
public function get count():int
{
return _count;
}
public function set count(value:int):void
{
_count = count;
}
I can from within another function call something like
count++;
which in turn sets _count to increase by one.
I.E I can seemingly access count through count or _count because I have a getter and setter..
That is correct understanding?
For something like the above is good OOP practice to have the getter and setter or simply call _count++;
Thanks
I will point out that your set count method changes the variable _points. If that is a typo, then:
Yes; that is a correct understanding. It sounds like your tests already proved that.
The private var _count will not be accessible by other classes with a reference to an instance of your class; but the public 'count' will be.
Getter and Setters are useful for performing other functionality within the class. In the context of a Flex UI Component, you may dispatch an event, or invalidate the component through one of the Flex component invalidation methods.
Separating out the get and set methods also allow you to create properties that are read only, or properties that are write only, just by leaving out the respective get or set method.
IF that is not a typo; then I have no idea why count++ would change the _count variable at all; and something else is going on with the count that you haven't shown us.
I am using a Cairngorm MVC architecture for my current project.
I have several commands which use the same type of function that returns a value. I would like to have this function in one place, and reuse it, rather than duplicate the code in each command. What is the best way to do this?
Create a static class or static method in one of your Cairngorm classes.
class MyStatic
{
public static function myFunction(value:String):String
{
return "Returning " + value;
}
}
Then where you want to use your function:
import MyStatic;
var str:String = MyStatic.myFunction("test");
Another option is to create a top level function (a la "trace"). Check out this post I wrote here.
You have lots of options here -- publicly defined functions in your model or controller, such as:
var mySharedFunction:Function = function():void
{
trace("foo");
}
... static methods on new or existing classes, etc. Best practice probably depends on what the function needs to do, though. Can you elaborate?
Create an abstract base class for your commands and add your function in the protected scope. If you need to reuse it anywhere else, refactor it into a public static method on a utility class.