Two questions:
Looking at the highlighted line in https://github.com/bwu-dart/bwu_datagrid/blob/master/example/src/composite_editor_item_details/app_element.dart#L120
1) why does the line
var idx = e.validationResults.errors.length;
always throws an error?
Exception: Uncaught Error: The null object does not have a getter 'length'.
NoSuchMethodError: method not found: 'length'
Receiver: null
Arguments: []
Stack Trace:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
#1 validationErrorHandler (http://localhost:8080/epimss_design.html.12.dart:184:42)
#2 _RootZone.runUnaryGuarded (dart:async/zone.dart:1020)
#3 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341)
#4 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:270)
#5 _SyncBroadcastStreamController._sendData (dart:async/broadcast_stream_controller.dart:346)
#6 _BroadcastStreamController.add (dart:async/broadcast_stream_controller.dart:237)
#7 EventBus.fire (package:bwu_datagrid/core/event_bus.dart:61:19)
#8 _commitCurrentEdit (package:bwu_datagrid/bwu_datagrid.dart:3626:25)
#9 EditorLock.commitCurrentEdit (package:bwu_datagrid/core/range.dart:235:82)
#10 BwuDatagrid._commitEditAndSetFocus (package:bwu_datagrid/bwu_datagrid.dart:3045:40)
#11 _handleKeyDown (package:bwu_datagrid/bwu_datagrid.dart:2632:39)
The same thing happens for other properties as well such as field and column etc.
2) How can I test that the validationResult returns true? The error handler seems to only fires when there is an ValidationError.
My validator is shown below
import 'package:bwu_datagrid/datagrid/helpers.dart' show Column, GridOptions,
MapDataItem, MapDataItemProvider;
import 'package:bwu_datagrid/bwu_datagrid.dart' show BwuDatagrid;
import 'package:bwu_datagrid/formatters/formatters.dart' show CheckmarkFormatter;
import 'package:bwu_datagrid/editors/editors.dart' show CheckboxEditor, EditorArgs,
IntegerEditor, TextEditor;
import 'package:bwu_datagrid/core/core.dart' show AddNewRow, ActiveCellChanged,
ItemBase, ValidationError;
import 'package:bwu_datagrid/plugins/row_selection_model.dart' show RowSelectionModel;
import 'package:epimss_podo/reg.dart' show Email, EMAIL_FORM_EVENT;
import 'package:epimss_shared/shared.dart' show toggleCoreCollapse, onBwuCellChangeHandler;
import 'package:epimss_shared/validators.dart' show BwuRequiredEmailValidator,
BwuRequiredNounValidator;
Custom validators:
const String REQUIRED_EMAIL_REGEX = r"\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b";
const String REQUIRED_NOUN_REGEX = r"\b[a-z'-]{2,}\b";
final RegExp _requiredNounValidator = new RegExp( REQUIRED_NOUN_REGEX, caseSensitive: false );
bool isRequiredNounValid( String property ) =>
_requiredNounValidator.hasMatch( property );
final RegExp _requiredEmailPropertyValidator = new RegExp( REQUIRED_EMAIL_REGEX, caseSensitive: false );
bool isRequiredEmailPropertyValid( String property ) => _requiredEmailPropertyValidator.hasMatch( property );
class BwuRequiredEmailValidator extends bwu.Validator {
bwu.ValidationResult call( dynamic value ) {
if ( isRequiredEmailPropertyValid( value ) ) {
return new bwu.ValidationResult( true );
} else {
return new bwu.ValidationResult( false, 'Valid email address required.' );
}
}
}
class BwuRequiredNounValidator extends bwu.Validator {
bwu.ValidationResult call( dynamic value ) {
if ( isRequiredNounValid( value) ) {
return new bwu.ValidationResult( true );
} else {
return new bwu.ValidationResult( false, 'Valid noun is required.' );
}
}
}
Validation error handler:
void validationErrorHandler( ValidationError e ) {
//print ( e.validationResults.errors.length );
print ( e.column.field );
if ( e.validationResults.isValid )
print( 'retVal is true' );
else
print( 'retVal is false' );
errorMsg = e.validationResults.message;
var editor = e.editor;
print ( 'valResult valid |' + e.validationResults.isValid.toString() );
var result = e.validationResults;
if ( e.validationResults.isValid ) {
errorMsg = 'EMAIL';
} else {
errorMsg = result.message;
}
print( editor.runtimeType ); // aslways print TextEditor
if ( editor != null ) {
//var colId = editor.column.id;
if ( editor is TypeEditor ) {
email.isTypeValid = true;
}
if ( editor is AddressEditor ) {
email.isAddressValid = false;
}
//print( encode ( email ) );
}
}
You get the exception because the field e.validationResults.errors is null.
You can't access the length property of null thus the exception is thrown.
The field errors is null because in this call
return new bwu.ValidationResult( false, 'Valid email address required.' );
you didn't pass a value for the optional errors parameter
class ValidationResult {
bool isValid = false;
String message;
List<ValidationErrorSource> errors;
ValidationResult(this.isValid, [this.message, this.errors]);
}
Hint:
As far as I know breakpoints don't work for code within <script> tags (I saw this in the example code I got in an email).
I therefore advise to move your code from the email_form.html file to a email_form.dart file.
Then you can use the debugger and investigate the values at runtime which also helps a lot to learn what others peoples code is actually doing.
Fire custom event from Editor
class AddressEditor extends bwu.TextEditor {
static const VALIDATION_SUCCEEDED = const EventType<ValidationError>(
'custom-validation-succeeded');
...
#override
bwu.ValidationResult validate() {
var result = super.validate();
args.grid.eventBus.fire(AddressEditor.VALIDATION_SUCCEEDED, new ValidationError(this,
editor: this,
cellNode: args.grid.getActiveCellNode(),
validationResults: result,
cell: args.grid.getActiveCell(),
column: column));
return result;
}
// you can register the same handler as for the validation error event
grid.eventBus.onEvent(AddressEditor.VALIDATION_SUCCEEDED).listen(validationErrorHandler);
I have not tried this code but it should work.
Related
I have Flutter mobile app that is using Riverpod with hooks.
I have the following function that I would like to be called when the widget is disposed:
useEffect(
() {
final firestoreRepo =
ref.read(firebaseFirestoreRepositoryProvider);
return () async {
try {
// I get exception at this line.
// I need this future to be called when the
// widget is disposed.
// Calling this future earlier is not userful
// for my business logic.
final relationship =
await ref.read(relationshipWithProvider(pid).future);
if (relationship?.unseen ?? false) {
await firestoreRepo?.updateRelatinoship(pid: pid);
}
} catch (e, st) {
// print error
}
};
},
[],
);
I keep getting this error at the line shown in the comment above.
I/flutter ( 5967): Looking up a deactivated widget's ancestor is unsafe.
I/flutter ( 5967): At this point the state of the widget's element tree is no longer stable.
How can I sold this problem
We can initially get our relationship and then await and use it:
useEffect(
() {
final firestoreRepo = ref.read(firebaseFirestoreRepositoryProvider);
final relationship = ref.read(relationshipWithProvider(pid).future);
return () async {
try {
if (await relationship?.unseen ?? false) {
await firestoreRepo?.updateRelatinoship(pid: pid);
}
} catch (e, st) {
// print error
}
};
},
[],
);
As far as I can tell, this won't contradict the logic of the business process, because one way or another, we'll have to make the relationshipWithProvider(pid) request early (when we initialize the widget) or late (when we delete the widget).
I have the follow problem: I need to consume a REST service (3rd party, not mine) and show the result data to the user using an Ext.grid.Panel.
The problem is I have no idea of the data structure and content ( it is a JSON from Geoserver's queryLayer ) so I can't have a store/grid/model field definition to respect the ExtJS MVC design.
So how can I be more flexible in this situation? I try to add a row to the grid by hand but after read https://www.sencha.com/forum/showthread.php?48625-how-can-i-insert-a-row-in-GRID I think it is a kind of crime to do
You can add a conversion layer for dynamic fields in the model class. The conversion will provide a string readable format for data you don't know the structure.
Ext.define('AppName.DynamicRow', {
extend: 'Ext.data.Model',
fields: [{
name: 'fixed1',
type: 'string'
}, {
name: 'fixed2',
type: 'string'
}, {
name: 'dynamic',
type: 'string',
calculate: function (data) {
Ext.Object.getAllKeys(data)
.map(function(key) {
return key + ': ' + data[key];
})
.join(', ');
}
}]
});
Then you will show all unstructured data in a grid column simply adding 'dynamic' field as dataIndex.
My workaround:
First, receive the data using a function to concentrate all creation stuff:
function addGrid ( title, data ) {
var storeColumns = getStoreColumnsFromJson( data[0] );
var gridColumns = getGridColumnsFromJson( data[0] );
var store = createStore( data, storeColumns );
var grid = createGrid( title, store, gridColumns );
myContainerWindowPanel.add( grid );
}
Now, I need to take a data sample (first row) to get the column names from the JSON data to the grid and its store:
function getStoreColumnsFromJson ( obj ) {
var keys = [];
for (var key in obj) {
if ( obj.hasOwnProperty(key) ) {
keys.push({name : key});
}
}
return keys;
}
function getGridColumnsFromJson ( obj ) {
var keys = [];
for (var key in obj) {
if ( obj.hasOwnProperty(key) ) {
keys.push({text: key, dataIndex: key});
}
}
return keys;
}
Now I'll create the grid and the store. I will not use the Model simply because this worked without it. If someone have a strong advice to create the model I'll appreciate.
function createGrid ( title, store, columnNames ) {
var dummyGrid = Ext.create('Ext.grid.Panel', {
border: false,
title : title,
store : store,
frame: false,
margin: "10 0 0 0",
flex:1,
loadMask: true,
columns:columnNames,
autoHeight:true
});
return dummyGrid;
}
function createStore ( storeData, columns ) {
var arrData = [];
var theData = storeData;
if ( !$.isArray( storeData ) ) {
arrData.push( storeData );
theData = arrData;
}
var store = Ext.create('Ext.data.Store',{
fields: columns,
autoLoad: true,
data: theData
});
return store;
}
I asked to fix an issue in software which use dart to develop a chrome application. currently, the chrome application doesn't run in my mac osx and I get the following exception:
Uncaught Unhandled exception:
Class '_InternalLinkedHashMap' has no instance method 'pushState'.
NoSuchMethodError: method not found: 'pushState'
Receiver: _LinkedHashMap len:0
Arguments: [null, "", "/index.html#events"]
#0 Object._noSuchMethod (dart:core-patch/object_patch.dart:42)
#1 Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
#2 Router._go (package:route/client.dart:153:22)
#3 Router.gotoPath (package:route/client.dart:139:7)
#4 Router.listen.<anonymous closure> (package:route/client.dart:111:13)
#5 wrap_event_listener.<anonymous closure>.<anonymous closure> (dart:html:1189)VM81:1 (anonymous function)
After I backtrace the issue, I found that listen() function instead of calling handle calls gotoPath(string,string). Can someone explain me that. this cause
[https://github.com/justinfagnani/route/blob/master/lib/client.dart][1]
void gotoPath(String path, String title) {
_logger.finest('gotoPath $path');
var url = _getUrl(path);
if (url != null) {
_go(path, title);
// If useFragment, onHashChange will call handle for us.
if (!_listen || !useFragment) {
_handlers[url](path);
}
}
}
void handle(String path) {
_logger.finest('handle $path');
var url = _getUrl(path);
if (url != null) {
// always give handlers a non-fragment path
var fixedPath = url.reverse(url.parse(path));
_handlers[url](fixedPath);
} else {
_logger.info("Unhandled path: $path");
}
}
this calls from here:
Note that other methods if/else call handle and only the !ignoreclick is call gotopath
void listen({bool ignoreClick: false}) {
_logger.finest('listen ignoreClick=$ignoreClick useFragment=$useFragment');
if (_listen) {
throw new StateError('listen should be called once.');
}
_listen = true;
if (useFragment) {
window.onHashChange.listen((_) {
var path = '${window.location.pathname}${window.location.hash}';
_logger.finest('onHashChange handle($path)');
return handle(path);
});
handle('${window.location.pathname}${window.location.hash}');
} else {
window.onPopState.listen((_) {
var path = '${window.location.pathname}${window.location.hash}';
_logger.finest('onPopState handle($path)');
handle(path);
});
}
if (!ignoreClick) {
window.onClick.listen((e) {
if (e.target is AnchorElement) {
AnchorElement anchor = e.target;
if (anchor.host == window.location.host) {
var fragment = (anchor.hash == '') ? '' : '${anchor.hash}';
gotoPath("${anchor.pathname}$fragment", anchor.title);
e.preventDefault();
}
}
});
}
}
I want to validate input corresponding to the following grammar snippet:
Declaration:
name = ID "=" brCon=BracketContent
;
BracketContent:
decCon=DecContent (comp+=COMPARATOR content+=DecContent)*
;
DecContent:
(neg=("!"|"not"))? singleContent=VarContent (op+=OPERATOR nextCon+=VarContent)*
;
My validation looks like that:
#Check
def checkNoCycleInHierarchy(Declaration dec) {
if(dec.decCon.singleContent.reference == null) {
return
}
var names = newArrayList
var con = dec.decCon.singleContent
while(con.reference != null) {
con = getThatReference(con).singleContent
if(names.contains(getParentName(con))) {
val errorMsg = "Cycle in hierarchy!"
error(errorMsg,
SQFPackage.eINSTANCE.bracketContent_DecCon,
CYCLE_IN_HIERARCHY)
return
}
names.add(getParentName(con))
}
}
But when I test this validation with a testCaseit returns me an error message:
Expected ERROR 'raven.sqf.CycleInHierarchy' on Declaration at [-1:-1] but got
ERROR (org.eclipse.emf.ecore.impl.EClassImpl#5a7fe64f (name: Declaration) (instanceClassName: null) (abstract: false, interface: false).0) 'Error executing EValidator', offset null, length null
ERROR (org.eclipse.emf.ecore.impl.EClassImpl#5a7fe64f (name: Declaration) (instanceClassName: null) (abstract: false, interface: false).0) 'Error executing EValidator', offset null, length null
I just can't figure out what's wrong with it so I hope that someone of you might have an idea.
Greetings Krzmbrzl
You test utility tells you that the validator did not produce the expected validation error ("CycleInHierarchy").
Instead, the validator produced the error "Error executing EValidator".
Which means an exception has been thrown when your validator was executed.
It turned out it was an internal error...I'm still not exactly sure what went wrong but I have rewritten my validation method and now it works as expected.
Now the method looks like this:
enter code here#Check
def checkNoCycleInHierarchy(Declaration dec) {
if(dec.varContent.reference == null) {
//proceed only if there is a reference
return
}
var content = dec.varContent
var names = newArrayList
while(content.reference != null && !names.contains(getParentName(content))) {
names.add(getParentName(content))
content = content.reference.varContent
if(names.contains(getParentName(content))) {
val errorMsg = "Cycle in hierarchy!"
error(errorMsg,
SQFPackage.eINSTANCE.declaration_BrCon,
CYCLE_IN_HIERARCHY)
return
}
}
}
I have the suspicion that there was a problem with the usage of my "getThatReference" in this case.
Greeting Krzmbrzl
I run the code below and I got an error without any stack trace.
My code:
typedef Check<T>(T value, [onError(T value)]);
main () {
List<Check> checks = [
(str) => str != null,
(str) => !str.isEmpty
];
Check<String> doCheck = (String value, [onError(String)]) {
checks.forEach((Check check) {
if (?onError) {
check(value, onError);
} else {
check(value);
}
});
};
doCheck("10");
}
And, the error I got.
file:///..()../sample.dart': Error: line 11 pos 12: formal parameter name expected
if (?onError) {
I want to get onError as an optional parameter in doCheck function, and pass this parameter to other functions in checks.
I confirmed to forward an optional parameter to 'one' function...
Is this one of restrictions to optional parameters?
I would say it is a bug (see issue 8007). To work around it, you have to use a temporary variable :
typedef Check<T>(T value, [onError(T value)]);
main () {
List<Check> checks = [
(str) => str != null,
(str) => !str.isEmpty
];
Check<String> doCheck = (String value, [onError(String)]) {
final isOnErrorPresent = ?onError;
checks.forEach((Check check) {
if (isOnErrorPresent) {
check(value, onError);
} else {
check(value);
}
});
};
doCheck("10");
}