I want to use document.querySelector method to get html node. In Js I can receive null as a result. But in F# the result type is Element and it's neither nullable nor optional and it's not clear how to check it for null. How can I handle the situation when querySelector doesn't match any DOM node?
Yes, it's true the F# code assumes Element is not nullable. You can trick the compiler to think otherwise in several ways. Probably the easiest one is to box the value like this:
let el = Globals.document.querySelector(".myclass")
if (box el) = null
then doSomething()
else doSomethingElse()`
box will be ignored when generating the JS code, so there's no performance penalty in doing this.
Related
Is there a better way to do this?
Assignment(
dueAt: json['due_at'] == null ?
null :
DateTime.parse(json['due_at']).toLocal()
)
The attribute "dueAt" in Assignment class can be null and i need to parse the string of json['due_at'] to a DateTime, but json['due_at'] can be null too.
Is not really a problem right now but seems noisy and repetitive.
First and foremost, it looks like you're writing JSON serialization code by hand. Your life will be much easier and less bug-prone if you let a library do this instead. json_serializable is very simple and powerful and 100% worth looking into.
However, this pattern is still common outside of json code.
You could also consider writing an extension method for Object? that behaves like the Kotlin standard library's let function (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/let.html)
You can then use Dart's ?. syntax to handle the rest of the logic:
// extension on T rather than Object? to maintain type information
extension Example<T> on T {
R let<R>(R Function(T) function) => function(this);
}
This just applies a given function to this, which isn't incredibly useful on it's own, but allows the use of ?.:
final DateTime? dueAt = json['due_at']?.let(DateTime.parse);
If json['due_at'] evaluates to null, the ?. operator short-circuits, and dueAt is set to null. Otherwise, it evaluates to DateTime.parse(json['due_at']).
Or, you could just use package:kt_dart which ports much of the Kotlin standard library to Dart
In this particular case you may want to use tryParse instead of parse. If dueAt is of type DateTime? you can simply call:
Assignment( dueAt: DateTime.tryParse(json['due_at'])?.toLocal() );
Be aware though that tryParse will return null for any invalid date string (be it null or an improperly formatted string). This may or may not be desired behavior depending on your intended use.
I found JavaFX to be suprisingly expressive after getting over the fact that I had to redeclare every field as property so I am a little stumped and would like to know if there is a better, more idomatic way of binding a boolean to some more complex operation like adding and removing style classes.
In this example I have a project that maybe valid or not and I want the font color of the tab to indicate which it is. I am doing this by adding and removing the error style class:
val errorSwitch = { valid : Boolean ->
logger.debug {"errorSwitcher: $valid"}
if( valid) tab.styleClass.remove("error")
else tab.styleClass.add("error")
Unit
}
product.isValid.onChange (errorSwitch)
errorSwitch(product.isValid.value)
What I don't like here is that I have to call the function once myself to start with because "onChange" obviously does not trigger unless the isValid actually changes. It's a small thing but I am wondering if there isn't a better way with bindings because thats what I want: the presence of the error class should be bound to "isValid"
In TornadoFX the best way to achieve this is to use the toggleClass function, which will automatically add or remove a given class based on a boolean observable value. Therefore you can simply say:
tab.toggleClass(Styles.error, product.isValid)
This example requires you to use the Type Safe CSS feature of TornadoFX. Read more about Type Safe CSS in the guide :)
This question has mostly been answered elsewhere, but I thought I would mention my experience with this because of an interesting side-effect the Dart guys might be interested in knowing.
enterPinDigits() {
Element pinDigits = document.getElementById('pinDigits');
pinDigits.value = "";
In the above, pinDigits is an HTML input element. When I code it as above, the editor tells me it doesn't recognize value as a valid field for the element.
HERE'S THE WEIRD PART:
This code behaves perfectly fine running in the Chromium/Dart environment, but it fails horribly when compiled to Javascript. Odd inconsistency.
getElementById returns a Node and the DartEditor can't know that it has an attribute value unless you state that it is an InputElement. If you make the variable of type Element it still has no value attribute.
var pinDigits = document.getElementById('pinDigits') as InputElement;
or
InputElement pinDigits = document.getElementById('pinDigits');
this way you also get proper autocompletion.
Dart2js uses type information for tree-shaking. It might drop the wrong code because of the wrong type annotation. In this case no type (var) is better than the wrong type. Actually Element isn't wrong so it might still be a bug.
I think I understand that this should be an InputElement, but I also found that a quick solution is to simply change the variable type from the Darty Element type to a generic var.
var pinDigits = document.getElementById('pinDigits');
But as this subject has been somewhat addressed elsewhere, this post is mostly meant to clarify the earlier post and to point out the odd inconsistency when running as Dart vs Javascript.
Before of the latest update, i wrote this code for example
<input type="text" id="link">
<p> {{variable}} </p>
// other code
var input = query('#link');
var variable = input.value;
This snippet of code still work, but anyone know why the editor reports this message?
"value" in not a member of Element
The Dart Editor reports that, because it thinks input variable is an instance of Element. Why? Because query() always returns an element, but the editor can't know that in your case, it's an input (of type InputElement).
You can ignore the warning. The IDE just can't know that the queried result is an InputElement, unless you tell it:
InputElement input = query('#link');
or I think this also works:
var input = query('input#link');
If you really want to tell the Dart runtime that you expect a variable to be of a certain type, you can use the cast operator: as. This has the advantage of informing the editor of the expected type, and it will also throw an error if the variable is not of the expected type.
var input = query('#link') as InputElement;
Note that Dart is a dynamic language, so I caution against using as unless you think other developers might be confused about your intent.
According to the documentation for Option.Value<'T>:
Get the value of a Some option. A NullReferenceException is raised if
the option is None.
and
This function is for use by compiled F# code and should not be used
directly.
Does the last sentence imply that it's due to interop? What's the use case if so?
Otherwise it seems very strange since the whole point of the Option type is to make the possibility of undefined values explicit and encourage handling of them, which easily can be circumvented:
let none : int option = None
let value = none.Value
I imagine it is there so that
match v with
|Some(t) -> t
works - without that Value property, you wouldn't be able to get the t with any functions which are available to F# code (Note there are some DU properties which are not accesible from F# which are an alternative here). There may also be some very minor speed benifits if you know that the option is Some as you don't check it if you use value directly