I have a simulation model that contains several schedules for moving the trucks between origin and destination stations. The inputs are created automatically by a Python script and in some cases, one or two of the schedules can be empty - meaning that I don't want the trucks move in those directions. An example is given below:
In such cases, the model throws the following error:
Is there a more elegant way of suppressing this error? (i.e. except giving a dummy row as input with all zeros)
The problem here is that since the scehdules are dragged onto the canvas they get created automatically when the Main agent gets created and you have no control over them... you can't do try() catch() and you also can't prevent them from being created if their tables are empty... or just let them be created with a blank value...
You have two options:
Option 1:
So you need to create the schedules programmatically - using the trick described in this article - you can get to the code used to create the schedules.
public Schedule<Integer> schedule = new Schedule<Integer>(
this, true, SUNDAY, 7L * TIME_UNIT_DAY, TIME_UNIT_DAY, null, 0, _schedule_Starts_xjal(), null, _schedule_Values_xjal(), false, null, true, true );
and then the schedule gets populated using
if (schedule.isInitialized()) {
new TableElementDatabaseBuilder(this).setSqlQuery("SELECT time, unit FROM truck_sc_ip").fillSchedule(
schedule,
Integer.class,
true,
true,
604800000L,
false,
false,
3600000L
);
}
You also need to create two variables for each schedule...
Object[] _schedule_Values_xjal() and Object[]_schedule_Starts_xjal()
There might be some other parts of the logic that gets created that I missed here but this should be sufficient.
Option 2:
The alternative is that you simply read in the entries into the DB and create your own Java class that you use as a schedule (my personal preference)
Related
According to https://www.ag-grid.com/javascript-grid-filter-set/, "The grid does not update the filters for you as there are too many use cases...", #agreed.
I am using a Server Side data source with Infinite Paging querying a large set of data. Although, at initial load time, I may be confident the filter is listing all available "choices", I am hoping to find a solution to "reload" the filter at some frequency/event to be certain.
I am attempting to use the resetFilterValues() method of the object returned by a call to gridOptions.api.getFilterInstance(id).
When using a Server Side data source I am receiving the following console.error output:
ag-Grid: Set Filter cannot initialise because you are using a row model that does not contain all rows in the browser. Either use a different filter type, or configure Set Filter such that you provide it with values (Source ag-grid-enterprise.min.js:555
Note: The values method with async value load works splendidly and is written in accordance with recommendation e.g. callback to params.success with values.
I load the filter choices in the Column Header using the following approach:
{
headerName: 'Something',
field: 'SOMETHING',
width: 200,
suppressMenu: false,
suppressFilter: false,
filter: 'agSetColumnFilter',
filterParams: {
values: function (params) {
someAsyncMethodReturningAPIResultsAsArray();
}
newRowsAction: 'keep'
},
menuTabs: ['filterMenuTab']
}
I then attempt to reload the filters at a later time (like when a button is pressed outside the grid) using the following code:
var filter = gridOptions.api.getFilterInstance(id);
filter.resetFilterValues();
This code results in the error expressed above.
Q: Does anyone know how to configure Set Model to return rows as described in the error message? Is there a better way to approach this problem anyone has experience with?
Thanks
This code below can be executed in the postProcessPopup callback and it will call the values() function defined in filterParams every time the popup is opened
var filter = gridOptions.api.getFilterInstance(id);
filter.refreshFilterValues();
Note: The refreshFilterValues function is doing the trick here. It is available in v24 and above. Not too sure about older versions.
I'm developing an event extension with recurring dates. Therefor, I have a recurring date pattern and copy the record for each date. So the record has a relation to itself:
- Main Event
-- N Child Events
Currently, I use the DataHandler method copyRecord, which works perfect. But this just copies the record, without mapping the relation.
- Main Event --> should have the count of children in the database
-- N Child Events --> should habe the relation to its parent main event
The DB should look like:
Event 1 (Main Event) | uid: 1 | event: 0 | recurring_children: 3 (count)
Event copy 1 | uid: 2 | event: 1 | recurring_children: 0
Event copy 2 | uid: 3 | event: 1 | recurring_children: 0
Event copy 3 | uid: 4 | event: 1 | recurring_children: 0
I tried several ways, but none without problems.
The following try sets the relation in the database, but creates more events (I guess, this loops and I have to build a condition to avoid filling the datamap with duplications):
public function processDatamap_afterDatabaseOperations(
$status,
$table,
$recordUid,
array $fields,
\TYPO3\CMS\Core\DataHandling\DataHandler $parentObject){
$event = BackendUtility::getRecord($table, $recordUid);
if ($status === 'update') {
/** #var \TYPO3\CMS\Core\DataHandling\DataHandler $tce */
$tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
$tce->start(array(), array());
$overrides = [
'is_recurring_parent' => 0,
'is_recurring_child' => 1,
'recurring_weekdays' => '',
'recurring_period_end' => '0000-00-00',
'event' => $recordUid,
'title' => 'FOOBAR'
];
if ($event['is_recurring_parent']) {
$foobar = $tce->copyRecord('tx_technoseumevents_domain_model_event', $event['uid'], $event['pid'], false, $overrides);
}
T3 version 8.7
Sorry, my first time I'm using the datahandler for complex tasks. Maybe someone has a hint for me...
The recursiveness happening in the first place, indicates a problem with your architecture that might be worth addressing before this problem as it would solve it at the root cause instead of treating symptoms. Normally, a record should not relate to itself - but that said, recursiveness can happen in other ways and it might not be possible to avoid in your use case.
Advise for addressing the problem:
Consider adding a condition that prevents your code from being called on tables other than the one table you need to operate on. This alone could actually be why your copies recurse so that's number one to handle.
If possible, and if you are not concerned with short-circuiting things like changing the title TCA field for a record to prepend "Copy of", or causing the copy to be hidden, you can switch to copyRecord_raw. It takes slightly different arguments (you may have to refactor to pass some arguments as part of the overrides array, compared to calling copyRecord). Doing that will prevent hooks from being called on the children you copy.
You are using a nested DataHandler instance - it might be preferable to call that method on the $dataHandler instance in your example. The DataHandler maintains a copy stack, but (parts of) it will only work if you do things in the same instance and only for some particular hooks (i.e. the pre-type and not-global hooks).
Lastly, there exists a runtime cache entry which contains an array of records which have been copied. Although the utility methods that access and store entries in this cache entry are not publicly accessible - so you cannot call them from your hook class - you can read the array of entries, manipulate it and put it back to prevent recursive processing of the same record. See the method isNestedElementCallRegistered in DataHandler (https://github.com/TYPO3/TYPO3.CMS/blob/v8.7.17/typo3/sysext/core/Classes/DataHandling/DataHandler.php#L9034).
Final note: the after-database-operations hook may be called at times when you do not expect it. For example, if you copy a record and also move it (as in: the copy comes from the UI, not programmatically) the array you receive in $fieldArray may not be the final one (for example, pid may be an unexpected value). Not being aware of this and the peculiarities above might also increase the danger of unintentionally causing recursive operations.
EDIT: If you are using bi-directional relations in TCA then removing one side may also improve the situation. For example, each "date" doesn't necessarily have to be aware of which event it is associated with. Something to consider.
I get an object from within an array in my model (a JSONmodel type) which is
{
"task": [
{
"dbid": 465,
"bk_cnt": 11,
}, {
"dbid": 472,
"bk_cnt": 16,
}
]
}
I bind this model to a table and connect the bk_cnt up to an objectNumber in a cell. No problem so far.
In code I want to change the value of the first bk_cnt value from 11 to 20 on press of a button. Inside the event I have:
var model = this.getView().getModel() // get the model
var tasks = model.getProperty("/task"); // get as a JS object
tasks[0].bk_cnt = 20 // update the model...will it update the view?
// model.refresh() // it will if this is uncommented.
Problem: Though it is bound to the view, the displayed value of bk_cnt does not change. if I add model.refresh() it does. This code is extracted from a larger section and one of the larger features is sorting by column click. When I click a column to re-sort (no change to the model), the value 20 appears.
What gives?
Musings: I have read that the model.getProprty() function returns a javascript object with a live reference back to the model, and that a change to the value of the object will automatically be reflected in the view for any bound controls. Does this statement fall down on array attributes ?
EDIT: Still feeling around the issue I find that
model.setProperty("/task/0/bk_cnt", 20)
Does not require a model.refresh() to update the view. Not a total surprise as this command is directly acting through the model. This leaves me thinking that the 'live' object returned by getProperty() is only live when it is a primitive datatype like a string or integer, but not for a JS object. Or am I missing something ?
EDIT 2: #Ash points out in his answer that there is a further approach which is to access the JS object from the model property, set whatever attributes need to be updated in the JS object, then replace that into the model, e.g.
var tasks = model.getProperty("/task");
tasks[0].bk_cnt = 20
model.setProperty('/task', tasks)
Second edit done to complete the trio of approaches for future readers.
The Model object is an abstraction layer ON TOP of a javascript object. There is no way that a change within an object is notified anywhere. You need to explicitly trigger the notifications through model.refresh() or model.setProperty().
So both of your solutions are valid, another one (which I favor) would be
var tasks = model.getProperty("/task");
tasks[0].bk_cnt = 20
model.setProperty('/task', tasks)
But this actually depends on how you bind your model to your UI objects :)
I am trying to create some joblets in Talend that will speed up some processes.
I have an input from a MSSQLInput, the results are then sorted and filtered a little. Then I have a tMemorizeRows and a tJavaFlex, the purpose of this is to memorize the rows in a column to preform a count. The count is based on a customer ID, once the the id changes the count starts back to 1 and the proccess begine again and continues to the end. I have refactored this as a joblet but it does not work, the error is:
ID_tMemorizeRows_1 cannot be resolved to a variable
I have a tJavaFlex which starts with
int counte = 1;
The Main code is
if(ID_tMemorizeRows_1[0].equals(ID_tMemorizeRows_1[1]))
{
counte = counte + 1;
}
else
{
counte = 1;
}
context.Enqnum = counte;
The Enqnum variable and is created correctly and added into a tMaps component.
Does anyone know why this is happening, one person told me it is because when you move something to a joblet it gets a new/different name so it has to be specifically called in the Java, if this is the case how do I find the name out?
Thank you
Rich
I do have a resolution. I have tried to add images however my reputation is not high enough.
When using joblets we know that Talend essentially recycles the code used in the joblet by inserting it into the code for the main job.
This is the joblet I have created, i know it works because I have refactored it to a joblet instead of building it from sctatch. What its doing is simply memorises row 0 and row 1 in an ordered data set, the java performs a count and the tMap appends the result to the job (as Mentioned above).
(I will try it inser image in my question, I do not have enough reputation point to insert it into a question).
When the job is run it runs fine. But problems occur when I want to reuse the same joblet in another part of the job. What Talend does is it assigns names within the source code to each component depending on the name of the joblet.
For example, if the Joblet was called ThisJob, then tMemorizeRows_1 would be called ThisJob_1_tMemorizeRows_1.
The row within the component (in this example ReferenceID) would renamed as:
ReferenceID_ThisJob_1_tMemorizeRows_1.
But when you add a second joblet to your job it gives it a new name, eg ThisJob_2. This name will be different depending on how much you have been altering your job before you add the second joblet. Therefore the number within the name will depend on this activity.
If you add the joblet into your job immediately then the joblet would be called ThisJob_2, if you have added 5 other components before you add it in then the joblet is likely to be called ThisJob_6 etc. (I'm not 100% sure how talend renames components)
When you add a joblet, You can see the name of the joblet on the joblet component, this then reverts back the the original joblet name when you create any links/joins to other components.
Its also important that each component within the code is assigned to a variable called currentComponent.
Resolution
What I did was used the Java code to split the name using the code below. This way I can get the current name of the of the joblet and use this name in my Java.
String string = currentComponent;
String[] parts = string.split("_");
String part1 = parts[0];
String part2 = parts[1];
String joblet = part1+'_'+part2;
String newrow = "ReferenceID_"+joblet+"_tMemorizeRows_1";
I hope this makes sense.
Thanks
I'm building a form with Yii that updates two models at once.
The form takes the inputs for each model as $modelA and $modelB and then handles them separately as described here http://www.yiiframework.com/wiki/19/how-to-use-a-single-form-to-collect-data-for-two-or-more-models/
This is all good. The difference I have to the example is that $modelA (documents) has to be saved and its ID retrieved and then $modelB has to be saved including the ID from $model A as they are related.
There's an additional twist that $modelB has a file which needs to be saved.
My action code is as follows:
if(isset($_POST['Documents'], $_POST['DocumentVersions']))
{
$modelA->attributes=$_POST['Documents'];
$modelB->attributes=$_POST['DocumentVersions'];
$valid=$modelA->validate();
$valid=$modelB->validate() && $valid;
if($valid)
{
$modelA->save(false); // don't validate as we validated above.
$newdoc = $modelA->primaryKey; // get the ID of the document just created
$modelB->document_id = $newdoc; // set the Document_id of the DocumentVersions to be $newdoc
// todo: set the filename to some long hash
$modelB->file=CUploadedFile::getInstance($modelB,'file');
// finish set filename
$modelB->save(false);
if($modelB->save()) {
$modelB->file->saveAs(Yii::getPathOfAlias('webroot').'/uploads/'.$modelB->file);
}
$this->redirect(array('projects/myprojects','id'=>$_POST['project_id']));
}
}
ELSE {
$this->render('create',array(
'modelA'=>$modelA,
'modelB'=>$modelB,
'parent'=>$id,
'userid'=>$userid,
'categories'=>$categoriesList
));
}
You can see that I push the new values for 'file' and 'document_id' into $modelB. What this all works no problem, but... each time I push one of these values into $modelB I seem to get an new instance of $modelA. So the net result, I get 3 new documents, and 1 new version. The new version is all linked up correctly, but the other two documents are just straight duplicates.
I've tested removing the $modelB update steps, and sure enough, for each one removed a copy of $modelA is removed (or at least the resulting database entry).
I've no idea how to prevent this.
UPDATE....
As I put in a comment below, further testing shows the number of instances of $modelA depends on how many times the form has been submitted. Even if other pages/views are accessed in the meantime, if the form is resubmitted within a short period of time, each time I get an extra entry in the database. If this was due to some form of persistence, then I'd expect to get an extra copy of the PREVIOUS model, not multiples of the current one. So I suspect something in the way its saving, like there is some counter that's incrementing, but I've no idea where to look for this, or how to zero it each time.
Some help would be much appreciated.
thanks
JMB
OK, I had Ajax validation set to true. This was calling the create action and inserting entries. I don't fully get this, or how I could use ajax validation if I really wanted to without this effect, but... at least the two model insert with relationship works.
Thanks for the comments.
cheers
JMB