Frontend Troubleshooting
This page covers common client-side issues in Serene/StartSharp applications and how to fix them.
Type Registration Failures
"The editor class 'X' was not found"
This error appears when the EditorTypeRegistry cannot find an editor type by its key. The error message itself suggests the fix:
The editor class "MyProject.MyModule.MyEditor" was not found.
Ensure that the editor type includes a line similar to the following (using the correct full name):
static [Symbol.typeInfo] = this.registerEditor("MyProject.MyModule.MyEditor");
Also, side-effect import this editor class from the current page.ts, grid.ts, or dialog.ts file. For example:
import "./path/to/MyEditor.ts";
After applying the fixes, build the project by running "npm run build" from the project folder.
Common causes:
- The editor is not registered with
registerEditor(orformatterTypeInfofor formatters). - The editor module is not side-effect imported — the class must be imported somewhere so its
static { registerType(this) }block runs. - The type name doesn't match the key used in the form/column metadata.
"The element already has widget 'X'!"
Only one widget of the same class can be attached to an element. If you create a second widget of the same class on the same element, this error is thrown. Use a different element, or destroy the existing widget first.
Missing Grid Refreshes
If a grid doesn't refresh after a dialog saves:
- The dialog must notify the grid via
SubDialogHelper.bindToDataChange(EntityGrid does this automatically). - Check that the dialog's
onSaveSuccessruns and that the grid'ssubDialogDataChange()is called. - If you open a dialog manually, bind it to the grid yourself:
SubDialogHelper.bindToDataChange(dialog, this, () => {
this.refresh();
});
Binding Issues
Editor value not loading/saving
- The editor must implement the value interfaces the form expects (
IGetEditValue/ISetEditValue, orIStringValue/IDoubleValue/IBooleanValue). - Check that the editor is registered with the correct interfaces:
static override[Symbol.typeInfo] = this.registerEditor("MyApp.MyEditor", [IGetEditValue, ISetEditValue]);
- For custom editors, verify
get_value/set_value(orgetEditValue/setEditValue) are implemented correctly.
Signal Updates Not Reflecting
If a signal-driven DOM update doesn't appear:
- Make sure the signal is actually being read inside the JSX (e.g.
{count}orclass={sig}), not just assigned once. - Check that the signal is being mutated via
.value = ..., not reassigned. - If the element was removed and re-added, the signal subscription may have been disposed — re-render the element.
Validation Not Working
- Validation rules are attached with
addValidationRuleand run on form submit. - A rule returns
null/empty for valid, a string for invalid. - If a field isn't validated, check that it has a
nameattribute and is inside the form.
Service Errors
"NotAuthorized" / session expired
- The user's session expired. Configure
Config.notLoggedInHandlerto redirect to login:
Config.notLoggedInHandler = () => window.location.href = "/Account/Login";
Service call fails with a validation error
- The server returned a
ServiceError. Handle it withtry/catchoronError:
try {
await MyService.Save(request);
}
catch (e) {
notifyError(e.Message);
}
See Also
- Frontend Patterns Cookbook — complete working examples.
- Type Registration — registering types.
- Data Binding — binding and change events.
- Signals and Reactivity — reactive updates.
- Custom Editors — validation and custom editors.
- Type-Safe Service Calls — service errors.
- Frontend Framework Overview — the three client-side packages and how they fit together.