Vaadin 14: sending data from a web component to server - vaadin

How can i send data from client to server using html5 webcomponent
setting up data from server to client, is very easy, works like a charm
how ever cannot find solution to send data to server
Please assist, but Iam not going to use Lit or Polymer
#JavaScript
class SimpleComponent extends HtmlElement {
connectedCallback() {
this.innerHTML = '<input type="text" id="test"/>";
this._input = this.querySelector('#test');
this._input.onchange = function() {
***** i want to send the value to server ****
})
}
setInputValue(value) {
this._input.value = value;
}
}
customElements.define("simple-com",SimpleComponent);
Now Java at Server
#Tag("simple-com")
class SimpleComponent extends Component {
public SimpleComponent() {
}
public void setValue(String value) {
getElement().callJsFunction("setValue",value);
}
}

The main challenge compared to Polymer or LitElement is that an event handler defined using the pattern innerElement.onchange = function() {} will not be run with this referencing the custom element instance. This in turn means that trying to use this.$server won't work because this isn't pointing to the expected value even though $server is indeed present in the place where it's supposed to be.
The easiest way of fixing this is to change the code to use an arrow function (() => {}) instead of an explicit function. This works because arrow functions inherit this from the scope where the function is defined whereas explicit functions have this defined in different ways depending on how it is run. Another approach would be to store a reference to this in a separate variable (e.g. let root = this) and then reference that variable instead of this in the function (e.g root.$server.doSomething()).
Putting everything together, this is what the code looks like with my modifications to make everything work.
class SimpleComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = '<input type="text" id="test"/>';
this._input = this.querySelector('#test');
this._input.onchange = () => {
this.$server.handleChange(this._input.value);
};
}
setValue(value) {
this._input.value = value;
}
}
customElements.define("simple-com", SimpleComponent);

Related

Notify server-side, an AbstractSinglePropertyField, of property change inside LitElement with Vaadin Flow

Up to at least Vaadin Flow 23 the official components are Polymer3 (from
what I saw), which is basically deprecated in favour of Lit.
Given a server side AbstractSinglePropertyField (see below for code),
that wraps a simple checkbox and is supposed to "mirror" a property
called checked from the client.
The server side then listens for checked-changed events from the
client, which Polymer3 happily fires for such a property.
Now consider the use of a webcomponent using Lit:
import {LitElement, html} from "lit-element";
export class MyCheckBox extends LitElement {
static get properties() {
return {checked: Boolean};
}
render() {
return html`<label><input type="checkbox" ?checked=${this.checked} #click=${this.toggleChecked}/>Toggle</label>`
}
toggleChecked(e) {
this.checked = e.target.checked;
}
}
customElements.define('my-checkbox', MyCheckBox);
Lit no longer automatically fires the checked-changed event.
So what is the official/easy/... way to deal with client-side property
changes and notify the server (which expects "Polymer3-style") about
them?
As of now, as a workaround, I fire my own event:
import {LitElement, html} from "lit-element";
export class MyCheckBox extends LitElement {
// ...
update(_changedProperties) {
super.update(_changedProperties);
this.fireChanged(_changedProperties, 'checked'); // XXX
}
fireChanged(_changedProperties, property) {
if (_changedProperties.has(property)) {
let htmlChangedEvent = new CustomEvent(property.concat("-changed"), {
detail: {
propertyName: property,
value: this.html,
oldValue: _changedProperties.get(property),
userOriginated: true
}
});
this.dispatchEvent(htmlChangedEvent);
}
}
}
customElements.define('my-checkbox', MyCheckBox);
The server side (for both client sides):
#Tag('my-checkbox')
#JsModule('./my-checkbox.js')
class MyCheckbox extends AbstractSinglePropertyField<MyCheckbox, Boolean> {
MyCheckbox() {
super('checked', false, false)
}
}
And a trivial test:
#Route("")
class MyForm extends Div {
MyForm() {
def mcb = new MyCheckbox().tap{
addValueChangeListener{
Notification.show("Value changed to ${it.value}")
}
}
add(mcb)
}
}
Without the firing of the "manual" checked-changed event, the
notification never shows.

SYMFONY FORM ChoiceType, multiple=>true. How to by pass the need to implement Data Transformers

In a SYMFONY FORM (ORM is not use (PDO is used for DB query instead)).
I have a class MyEntityType in which the buildForm function has:
$builder->add('my_attribute',ChoiceType::class,array(
'choices'=>$listForMyAttribute,
'multiple'=>'true',
'attr'=>array('data-native-menu'=>'false'),
'label'=>'Multiple Select on my attribute'
));
My attribute is an array of an entity named MyEntity which has:
/**
* #Assert\NotBlank()
*/
private $myAttribute;
With a getter and a setter for that variable $myAttribute.
When I submit the form in the Controller, it doesn't pass the validation check and logs this error:
Unable to reverse value for property path "myAttribute" : Could not find all matching choices for the given values.
When I start to look for solution around this error message, it leads to something named "How to Use Data Transformers" in SYMFONY Cookbook; And it seems a solution would involve to create new Class and write a lot of code for something that one should be able to by-pass in a much straight forward way.
Does anyone have an idea?
My problem was that my array $listForMyAttribute was defined in the buildForm() function and its definition was relying on some conditional.
The conditional to make the array were met when this one was displayed for the first time.
After pushing the submit button, the buildForm was regenerated in the Controller, this second time, the condition were not met to make the array $listForMyAttribute as it was on the first display. Hence the program was throwing a "contraint not met error" because the value submited for that field could not be find.
Today I face exactly the same problem. Solution is simple as 1-2-3.
1) Create utility dummy class DoNotTransformChoices
<?php
namespace AppBundle\DataTransformer;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
class DoNotTransformChoices implements ChoiceListInterface
{
public function getChoices() { return []; }
public function getValues() { return []; }
public function getPreferredViews() { return []; }
public function getRemainingViews() { return []; }
public function getChoicesForValues(array $values) { return $values; }
public function getValuesForChoices(array $choices) { return $choices; }
public function getIndicesForChoices(array $choices) { return $choices; }
public function getIndicesForValues(array $values) { return $values; }
}
2) Add to your field the following additional option:
...
'choice_list' => new DoNotTransformChoices,
...
3) Congratulations!

Implement an Observer pattern in Dart

I would like to implement an observer pattern in Dart but I'm not sure how to go about it.
Let's say I have a class:
class MyClass {
String observed_field;
}
Now, whenever I change the field, I'd like to print "observed_field changed" string into the console. Pretty simple to do with a custom setter:
class MyClass {
String _observed_field;
get observed_field => _observed_field;
set observed_field(v) {
_observed_field = v;
print("observed_field changed");
}
}
Now, of course, if I have not one, but many of those fields, I wouldn't want to create all those getters and setters. The obvious theoretical solution is to have them dynamically added to the class with something like this (not a working code, just an example of how I wish it looked):
class MyClass
String _observeable_field;
String _observeable_field_2;
observe(#observeable_field, #observeable_field_2);
end
Is it even possible? Additionally, it would be super awesome to not have those fields defined above the observe() call, but rather write something like:
observe(String: #_observeable_field, String: #_observeable_field_2);
So that those fields are declared automatically.
Here's a way to do it using the Observe package. The example is taken from code comments in that package (and adapted to your example above). Essentially, you annotate fields you want to be observable with the #observable annotation, and then listen for changes (which you trigger with the call to Observable.dirtyCheck();
First, add the observable package in your pubspec.yaml
dependencies:
observe: any
Then create a quick test program...
import 'package:observe/observe.dart';
class MyClass extends Object with Observable {
#observable String observedField = "Hello";
toString() => observedField.toString();
}
main() {
var obj = new MyClass();
// anonymous function that executes when there are changes
obj.changes.listen((records) {
print('Changes to $obj were: $records');
});
obj.observedField = "Hello World";
// No changes are delivered until we check for them
Observable.dirtyCheck();
print('done!');
}
This produces the following output:
Changes to Hello World were: [#<PropertyChangeRecord Symbol("observedField") from: Hello to: Hello World>]
done!
Update in response to comments...
Updating the example to omit the Observable.dirtyCheck() you can use a setter and notifyPropertyChanged, with the class instead mixing in ChangeNotifier
class MyClass2 extends Object with ChangeNotifier {
String _observedField = "Hello";
#reflectable get observedField => _observedField;
#reflectable set observedField(v) {
_observedField = notifyPropertyChange(#observedField, _observedField, v);
}
toString() => observedField;
}

Loading classes dynamically in Dart

So, I looked into mirror and they might be an option, but given their async nature they might be really awkward to use or just not viable in the long run. Since they are currently not supported (just a play-thing) they are not really viable at this time anyway.
Question: Given a series of Strings, eg. [ "Foo", "Bar" ] a base class Application and Widget in library corelib; and a corresponding class for each of the strings FooWidget, BarWidget in library applibrary;, what's currently the most elegant method to get Application to turn the strings into instances of the corresponding classes, that works with dart2js.
Equivalent PHP pseudo-example for clarity,
<?php # example
namespace corelib;
class Widget {
function name() {
return \get_called_class();
}
}
class Application {
static function resolve($name, $library) {
$class = $library.'\\'.$name.'Widget';
return new $class;
}
}
namespace applibrary;
class FooWidget extends \corelib\Widget {
// ...
}
class BarWidget extends \corelib\Widget {
// ...
}
$foowidget = \corelib\Application::resolve('Foo', 'applibrary');
$barwidget = \corelib\Application::resolve('Bar', 'applibrary');
echo "{$foowidget->name()} <br> {$barwidget->name()}";
Output
applibrary\FooWidget
applibrary\BarWidget
If you can validate the list of strings, then the best way for the moment (until mirror support in dart2js becomes better baked), is likely an if statement.
// toy implementation
Widget getWidget(name) {
switch (name) {
case "Foo": return new FooWidget();
case "Bar": return new FooWidget();
default: // handle error
}
}
// elsewhere:
var fooWidget = getWidget("Foo");
var barWidget = getWidget("Bar");
The list of xyzWidget classes will be a finite list (as you can't dynamically link in code at runtime anyway).
Of course, a more elegant implementation is to use mirrors (shown below, for reference, although it doesn't currently fulfil the dar2js criteria)
Future<Widget> getWidget(library, name) {
var completer = new Completer<Widget>();
MirrorSystem ms = currentMirrorSystem();
ClassMirror cm = ms.libraries[library].classes[name];
// instantiate an instance of the class
cm.newInstance(null,[]).then((instance) => completer.complete(instance));
return completer.future;
}
// elsewhere:
getWidget("applibrary","FooWidget").then((Widget widget) {
// do something with widget
});

Define a custom jQuery UI widget in TypeScript

We're currently looking at translating our JavaScript project to TypeScript. Our application relies heavily on custom developed jQuery UI widgets.
In our current code base, we're using a deep copy mechanism to inherit from widget definitions allowing us, for example, to declare a generic TableWidget as well as an OrdersTableWidget which defines more specific functions.
Therefore, I'd like to define my widget definitions as TypeScript classes and then bind an instance of these classes to jQuery.
For example
class MyWidget {
options: WidgetOptions;
_init(){
// general initialization
}
}
class MySecondWidget extends MyWidget {
_init(){
super._init();
// specific initialization
}
}
And then
$.widget("MyNameSpace.MyWidget", new MyWidget());
$.widget("MyNameSpace.MySeWidget", new MyWidget());
Furthermore, I'd like to denote my custom widgets as implementations of jQuery UI's Widget definition
class MyWidget implements Widget {
options: WidgetOptions;
_init(){
// general initialization
}
}
so I'm able to use the following syntax in TypeScript:
$(selector).MyWidget(options);
I know I have to work with the definition file (from DefinitelyTyped), however I have not yet found a reliable source explaining me how I should write custom jQuery UI Widgets in TypeScript. Has anyone got experience with this?
Any help greatly appreciated, as always!
I'm not sure you can write a class that implements the Widget interface, due to the lack of overloaded constructors. You could create a variable that is typed by the Widget interface.
A standard jQuery plugin would be represent in almost pure JavaScript and wouldn't use modules or classes as it ends up being wrapped up as part of jQuery, which itself isn't a module or class.
Here is an empty plugin called plugin that looks like any standard jQuery plugin, but you can see it takes advantage of the TypeScript type system and extends the JQuery interface to allow it to be called.
/// <reference path="jquery.d.ts" />
interface JQuery {
plugin(): JQuery;
plugin(settings: Object): JQuery;
}
(function ($) {
function DoSomething(someParamater: string) : void {
}
$.fn.plugin = function (settings) {
var config = {
settingA: "Example",
settingB: 5
};
if (settings) {
$.extend(config, settings);
}
return this.each(function () {
});
};
})(jQuery);
This would be called in the normal way.
$('#id').plugin();
So really, my answer is - you can't really do what you want because you are adding to the declared interfaces for jQuery rather than exposing them as modules. You could wrap the usage in a module, like an adaptor that abstracts the jQuery aspect away from the use in your TypeScript, or you can call your classes from inside the plugin, but the plugin or widget doesn't really fit into a module or class.
It might help to have a base class in typescript from which other widget classes may derive.
Its only purpose is to provide the base class semantic so you can access the base class'es members without having to resort to weak typing.
The trick is to remove all the members at runtime (in the constructor) -- otherwise you run into problems with the inheritance provided by the widget factory. For example, the option method would override the widget's original method which is not desired: we just want to be able to call it (in a statically typed way).
class WidgetBase {
public element:JQuery;
constructor() {
// remove all members, they are only needed at compile time.
var myPrototype = (<Function>WidgetBase).prototype;
$.each(myPrototype, (propertyName, value)=>{
delete myPrototype[propertyName];
});
}
/**
* Calles the base implementation of a method when called from a derived method.
* #private
*/
public _super(arg1?:any, arg2?:any, arg3?:any, arg4?:any) {
}
/**
* #private
*/
public _superApply(arguments) {
}
/**
* Gets or sets the value of the widget option associated with the specified optionName.
*/
public option(optionName:string, value?:any):any {
}
// ... further methods from http://api.jqueryui.com/jQuery.widget/
}
Then you can implement your own widget like this:
class SmartWidget extends WidgetBase {
constructor(){
super();
}
public _create() {
var mySmartOption = this.option('smart'); // compiles because of base class
this.beSmart(mySmartOption);
}
public _setOption(key:string, value:any) {
if (key === 'smart') {
this.beSmart(value);
}
this._super(key, value); // compiles because of base class
}
private beSmart(smartOne:any){
// ...
}
}
// register
jQuery.widget("myLib.smartWidget", new SmartWidget());
// assuming you are using https://github.com/borisyankov/DefinitelyTyped
declare interface JQuery{
smartWidget();
smartWidget(options:any);
smartWidget(methodName:string, param1?:any, param2?:any, param3?:any, param4?:any);
}
And finally, you can use your widget:
$(".selector").smartWidget({smart:"you"});

Resources