Solution Model 'clone' error

I create a a new form via the Solution Model and change some objects on it later with methods as well. This all works fine, the first time. When I run this last method again I get the following error:

“Persist ipm_cal_weekview already a clone”

Where ipm_cal_weekview is the dynamically created form name.

This is the code:

function ipm_week_calendar_changeEvent()
{
	var _sForm	= "ipm_cal_weekview",
		_oForm,
		_oLabel;

	if ( forms[_sForm] ) {
		_oForm 		= solutionModel.getForm(_sForm);
		if ( history.removeForm(_sForm) ) {
			if ( solutionModel.removeForm(_sForm) ) {
				// Simple action, just move this label.
				_oLabel		= _oForm.getLabel("event1");
				_oLabel.x	= _oLabel.x + _oLabel.width + 1; // HERE IT ERRORS OUT THE SECOND TIME YOU RUN THIS
				forms[_sForm].controller.show(); // show the form
			} else {
				application.output("ipm_cal_weekview_changeEvent ==> couldn't remove form"); // debug
			}
		} else {
			application.output("ipm_cal_weekview_changeEvent ==> couldn't remove form from history"); // debug
		}

	}
}

As you see I already added a bunch of checks to see if the form can be removed before I work on it.
All the methods are on another form and I move away from the dynamic form before this method is triggered.
The variable _oLabel is also not null when the error occurs
Anyone got any ideas ?

Hi Robert,

I just tested your code and I was never able to remove the form with the line:
if ( solutionModel.removeForm(_sForm) ) {

Even though I was not showing it or referencing it in any way.
So I guess that it’s because it was a “real” form that the solutionModel.removeForm refused to work as such…

Anyway, doing it a little bit differently, I manage to make this thing work:

function ipm_week_calendar_changeEvent()
{
   var _sForm   = "ipm_cal_weekview",
      _oForm,
      _oLabel;

   if ( forms[_sForm] ) {
       if ( history.removeForm(_sForm) ) {
            _oForm       = solutionModel.revertForm(_sForm);
            // Simple action, just move this label.
            _oLabel      = _oForm.getLabel("event1");
            _oLabel.x   = _oLabel.x + _oLabel.width + 1; // NO ERRORS
            forms[_sForm].controller.show(); // show the form
      } else {
         application.output("ipm_cal_weekview_changeEvent ==> couldn't remove form from history"); // debug
      }

   }
}

I’m not entirely sure that I was in the same condition as you are, but if that’s what you are trying to achive, this should work.

Hope this helps,

Hi Patrick,

ptalbot:
Hi Robert,

I just tested your code and I was never able to remove the form with the line:
if ( solutionModel.removeForm(_sForm) ) {

Even though I was not showing it or referencing it in any way.
So I guess that it’s because it was a “real” form that the solutionModel.removeForm refused to work as such…

Yeah, when you use a form that was created manually (as apposed to dynamically) then you can’t remove it. My form was created completely dynamically.

ptalbot:
Anyway, doing it a little bit differently, I manage to make this thing work:

function ipm_week_calendar_changeEvent()

{
var _sForm = “ipm_cal_weekview”,
_oForm,
_oLabel;

if ( forms[_sForm] ) {
if ( history.removeForm(_sForm) ) {
_oForm = solutionModel.revertForm(_sForm);
// Simple action, just move this label.
_oLabel = _oForm.getLabel(“event1”);
_oLabel.x = _oLabel.x + _oLabel.width + 1; // NO ERRORS
forms[_sForm].controller.show(); // show the form
} else {
application.output(“ipm_cal_weekview_changeEvent ==> couldn’t remove form from history”); // debug
}

}
}

So you can run this multiple times on that form and no errors ?
For me I can only run it once. The second time I run this I get that error.

Yes I can call it any number ot times, but then as you said my form was created “manually” (it exists in the Solution Explorer).
But I have done what you do, using a form created dynamically from scratch, and then I got the error.
Now looking at the sequence of your code, I would say that it is normal…
I added a function to create the form:

function createForm()
{
	var _sForm   = "ipm_cal_weekview";
	var _oForm = solutionModel.newForm(_sForm,controller.getServerName(),controller.getTableName(),null,false,800,600);
	var _oLabel = _oForm.newLabel("Event 1 text",100,100,140,20);
	_oLabel.name = "event1";
}

Then in your function, I got the error, but I disappears if I call my createForm() before trying to use it again:

function ipm_week_calendar_changeEvent()
{
   var _sForm   = "ipm_cal_weekview",
      _oForm,
      _oLabel;

   if ( forms[_sForm] ) {
      if ( history.removeForm(_sForm) ) {
         if ( solutionModel.removeForm(_sForm) ) { // THIS IS WHERE YOU THROW YOUR FORM OUT!
             createForm(); // YOU NEED TO CALL YOUR FORM'S CREATION METHOD AGAIN, SINCE YOU DESTROYED IT ON THE LINE ABOVE!
             _oForm       = solutionModel.getForm(_sForm);
            // Simple action, just move this label.
            _oLabel      = _oForm.getLabel("event1");
            _oLabel.x   = _oLabel.x + _oLabel.width + 1; // NO ERRORS BECAUSE THE LABEL HAS A REAL REFERENCE HERE
            forms[_sForm].controller.show(); // shows the form
         } else {
            application.output("ipm_cal_weekview_changeEvent ==> couldn't remove form"); // debug
         }
      } else {
         application.output("ipm_cal_weekview_changeEvent ==> couldn't remove form from history"); // debug
      }

   }
}

I think that the problem with your method was in the call to solutionModel.removeForm: you were first putting the form into an _oForm object, then removing the form from history, then from the solutionModel, meaning that your _oForm at this time was still ok, but new calls to solutionModel.getForm() were resulting in referencing garbage, since you destroyed the forms blueprint the first time!

Hi Patrick,

If I have to rebuild the form every time I want to change 1 little thing on it is not very efficient. And in fact this is how it always worked before 4.1.3.
Perhaps the changes in 4.1.3 now require you to recreate the form from scratch, I dunno. Perhaps Johan or Jan Blok can shed some light on this.

And like I said, I can run the method once. I have checks for if the form can’t be removed from history or from memory. It passes all the checks and when run for the second time I get this ‘clone’ error.

Hi Robert,
do you mean that the above code was working “as-is” in Servoy before 4.1.3?
Because if you don’t want to recreate the form, all you need to do is not to remove it from the solutionModel…

This code works for me:

var _sForm   = "ipm_cal_weekview",
      _oForm,
      _oLabel;

if ( forms[_sForm] ) {
    if ( history.removeForm(_sForm) ) {

	_oForm       = solutionModel.getForm(_sForm);
	
	// Simple action, just move this label.
	_oLabel      = _oForm.getLabel("event1");
	_oLabel.x   = _oLabel.x + _oLabel.width + 1;
	forms[_sForm].controller.show(); // show the form
	
    } else {
	 application.output("ipm_cal_weekview_changeEvent ==> couldn't remove form from history"); // debug
    }
}

ptalbot:
Hi Robert,
do you mean that the above code was working “as-is” in Servoy before 4.1.3?
Because if you don’t want to recreate the form, all you need to do is not to remove it from the solutionModel…

Ah! Now it works. Okay, all the talk about non-referencing a form before doing anything with it made me think I had to remove it from memory first.
But in fact I don’t even have to -not- show the form at all to change something on it. Very cool! :D

Thanks for thinking along with me!

If you call solutionModel.removeForm(_sForm)

Then your really destroy the blueprint, so there is no form anymore in the blueprint that can be made an instance of.
So if you want to have/alter the “_sForm” again
you really need to create it again in the blueprint by newForm on solutionModel

So if you constantly want to create a new Form under the same name you have to do both (remove and new)

just a tip: If you do use solutionModel.removeForm() you dont really need to have to do history.removeForm() we do that for you and if that fails then we dont remove it.

But if you just want to change a previously generated form then you can just get it and alter it

Of course you have to call history.removeForm() first so that you dont get the “Stale form(s) detected, …” error
In servoy 5.0 we have a new method for this that makes it a bit easier and keeps way more state see controller.recreateUI()

If this all is a existing form that you alter and you want to do that completely again. then we call revertForm()
and if you do that then do use the return value of revertForm as the JSForm object that you want to alter

So never after sm.removeForm or sm.revertForm use a JSForm object that you have get before that call for that form that you do remove or revert