I'm a rookie Dartisan. I've pushed test project on https://github.com/mackristof/DartWebComponentCommunication .
I want to find the best implementation for communication between 2 web components.If user click button on webComponent 1, how can counter webcomponent 2 can be informed ? Stream ? Bus-Event ?
Thxs for pull request with best solution.
Christophe.
For this type of communication I have implemented an event bus, and it has been quite useful for me.
If the event bus is defined at the app level, your event can look something like this;
void increment() {
eventBus.fire(clickEvent, 1)
}
And your counter component can be backed by a model object something like;
class CounterComponent extends WebComponent {
int get count => viewModel.count;
ViewModel viewModel;
}
and the ViewModel can look something like
class ViewModel{
int count;
ViewModel(){
eventBus.on(clickEvent).listen((msg){
count = count + msg;
});
}
}
I think web components can talk to each other through the parent/host DOM using events. When one web component will trigger some event, host/parent DOM should catch it and inform the other web components by changing their attribute values.
This way I think web components can communicate.
Related
I have a widget to represent list of stores sorted by nearest to the user current locations also filtering should be applied.
Data in:
Stores data coming from stream of Firestore collection
Current user location from geolacator.
Filtering options from shared preferences
(can be changed any time)
List sorting mode selected by user
Data out: Filtered, sorted, list of stores.
What pattern is best practice in this case?
rxdart : https://pub.dartlang.org/packages/rxdart
if you wanna combine data together you can use
var myObservable = Observable.combineLatest3(
myFirstStream,
mySecondStream,
myThirdStream,
(firstData, secondData, thirdData) => print("$firstData $secondData $thirdData"));
you can combine from ( combineLatest2, combineLatest... combineLatest9 )
or
CombineLatestStream
like this example
CombineLatestStream.list<String>([
Stream.fromIterable(["a"]),
Stream.fromIterable(["b"]),
Stream.fromIterable(["C", "D"])])
.listen(print);
Numbers 2, 3 and 4 are inputs to the bloc that you'd send in through sinks. The bloc listens on those sinks and updates the Firestore query accordingly. This alone might be enough to make Firestore send the appropriate snapshots to the output stream the widget is listening to.
If you can't sort or filter how you want directly with Firestore's APIs, you can use stream.map or apply a StreamTransformer on it. The transformer gives you a lot of flexibility to listen to a stream and change or ignore events on the fly by implementing its bind method.
So you can do something like:
Stream<Store> get stores => _firestoreStream
.transform(filter)
.transform(sort);
Have a look at this page for streams in dart in general, and look into rxdart for more complex stream manipulations.
From personal experience I found having multiple inputs to a block leads to hard to test code. The implicit concurrency concerns inside the block lead to confusing scenarios.
The way I built it out in my Adding testing to a Flutter app post was to create a single input stream, but add markers to the messages notating which data stream the message was a part of. It made testing sane.
In this situation, I think there are multiple asynchronous processing. This implementation can be complicated. And there is a possibility of race condition.
I will implement as follows.
Separate streams of Model from Firestore and user-visible ViewModel in Bloc. Widgets listen to only ViewModel.(eg. with StreamBuilder)
Limit Business logic processing only in Bloc. First, relocate processing with SharedPreferences into Bloc.
Create UserControl class just for user input.
Branch processing depends on user input type of extended UserControl
I hope you this will help you.
For example:
import 'dart:async';
import 'package:rxdart/rxdart.dart';
class ViewModel {}
class DataFromFirestoreModel {}
abstract class UserControl {}
class UserRequest extends UserControl {}
class UserFilter extends UserControl {
final String keyWord;
UserFilter(this.keyWord);
}
enum SortType { ascending, descending }
class UserSort extends UserControl {
final SortType sortType;
UserSort(this.sortType);
}
class Bloc {
final controller = StreamController<UserControl>();
final viewModel = BehaviorSubject<ViewModel>();
final collection = StreamController<DataFromFirestoreModel>();
Bloc() {
controller.stream.listen(_handleControl);
}
_handleControl(UserControl control) {
if (control is UserRequest) {
_handleRequest();
} else if (control is UserFilter) {
handleFilter(control.keyWord);
} else if (control is UserSort) {
handleSort(control.sortType);
}
}
_handleRequest() {
//get location
//get data from sharedPreferences
//get data from firestore
ViewModel modifiedViewModel; // input modifiedViewModel
viewModel.add(modifiedViewModel);
}
handleSort(SortType sortType) {
final oldViewModel = viewModel.value;
//sorting oldViewModel
ViewModel newViewModel; // input sorted oldViewModel
viewModel.add(newViewModel);
}
handleFilter(String keyWord) {
//store data to sharedPreferences
//get data from Firestore
ViewModel modifiedViewModel; // input modifiedViewModel
viewModel.add(modifiedViewModel);
}
}
In my controller, via service, I get from DB a list of the names of widgets (eg. chart, calendar, etc). Every widget implements WidgetInterface and may need other services as its own dependencies. The list of widgets can be different for each user, so I don't know which widgets / dependencies I will need in my controller. Generally, I put dependencies via DI, using factories, but in this case I don't know dependencies at the time of controller initialization.
I want to avoid using service locator directly in controller. How can I manage that issue? Should I get a list of the names of widgets in controller factory? And depending on widgets list get all dependencies and put them to controller?
Thanks, Tom
Solution
I solved my issue in a way that suggested Kwido and Sven Buis, it means, I built my own Plugin Manager.
Advantages: I do not need use service locator directly in controller and I have clear and extensible way to get different kinds of widgets.
Thank you.
Create your own Manager, like some sort of ServiceManager, for your widgets.
class WidgetManager extends AbstractPluginManager
Take a look at: Samsonik tutorial - pluginManager. So this way you can inject the WidgetManager and only retrieve the widgets from this manager as your function: validatePlugin, checks whether or not the fetched instance is using the WidgetInterface. Keep in mind that you can still call the parent ServiceManager.
Or keep it simple and build a plugin for your controller that maps your widget names to the service. This plugin can then use the serviceLocator/Manager to retrieve your widget(s), whether they're created by factories or invokableFactories. So you dont inject all the widget directly but only fetch them when they're requested. Something realy simplistic:
protected $map = [
// Widget name within the plugin => Name or class to call from the serviceManager
'Charts' => Widget\Charts::class,
];
public function load($name)
{
if (array_key_exists($name, $this->map)) {
return $this->getServiceManager()->get($this->map[$name]);
}
return null;
}
Injecting all the Widgets might be bad for your performance so you might consider something else, as when the list of your widgets grow so will the time to handle your request.
Hope this helped you and pushed you in some direction.
This indeed is a interesting question. You could consider using Plugins for the widgets, which can be loaded on the fly.
Depency injection is a good practise, but sometimes, with dynamic content, impossible to implement.
Another way to do this, is to make your own widget-manager. This manager then can load the specific widgets you need. The widget-manager can be injected into the controller.
Edit:
As you can see above, same idea from #kwido.
I would use a separate service and inject that into the controller.
interface UserWidgetServiceInterface
{
public function __construct(array $widgets);
public function getWidget($name);
}
The controller factory
class MyControllerFactory
{
public function __invoke(ControllerManager $controllerManager, $name, $requestedName)
{
$serviceLocator = $controllerManager->getServiceLocator();
$userWidgetService = $serviceLocator->get('UserWidgetService');
return new MyController($userWidgetService);
}
}
Then the logic to load the widgets would be moved to the UserWidgetServiceFactory.
public function UserWidgetServiceFactory
{
public function __invoke(ServiceManager $serviceLocator, $name, $requestedName)
{
$userId = 123; // Load from somewhere e.g session, auth service.
$widgetNames = $this->getWidgetNames($serviceLocator, $userId);
$widgets = $this->loadWidgets($serviceManager, $widgetNames);
return new UserWidgetService($widgets);
}
public function getWidgetNames(ServiceManager $sm, $userId)
{
return ['foo','bar'];
}
public function loadWidgets(serviceManager $sm, array $widgets)
{
$w = [];
foreach($widgets as $widgetName) {
$w[$widgetName] = $sm->get($widgetName);
}
return $w;
}
}
The call to loadWidgets() would eager load all the widgets; should you wish to optimise this you could register your widgets as LazyServices
Just started doing some code porting from .Net CF to Blackberry JDE 4.6.1. But haven't found how to implement custom events.
I have a custom syncManager that raise events in .Net CF so I can update the UI (sort of the observer patron).
Any pointers or help where I can start?
I can recommend the j2me-observer project. It has a liberal license and will give you an implementation of the observer pattern which isn't included in J2ME. It can be used to allow UI changes to happen based on fired events.
you can send custom event using.
//you can use any int value for CUSTOM_EVENT
fieldChangeNotify(CUSTOM_EVENT);
and you can handle that event using
public void fieldChanged(Field field, int context) {
if(cotext == CUSTOM_EVENT){
Dialog.alert("custom event");
}
}
I can recommend the open source project javaEventing. It's available at http://code.google.com/p/javaeventing , and makes it easy to define, register for and trigger custom events, much like in C#.
An example:
Class MyEvent extends EventManager.EventObject {}
EventManager.registerEventListener(new EventManager.GenericEventListener(){
public void eventTriggered(Object sender, Event event) {
// <-- The event is triggered, do something.
}
}, new MyEvent());
EventManager.triggerEvent(this, new MyEvent()); // <-- Trigger the event
bob
Background: 3-4 weeks experience in Silverlight3/C#/.Net and about 3days worth with the RIA Services concept. (most of my previous questions up to date should explain why)
I am doing a test implementation of Microsoft's RIA services with Silverlight3. This is part of a proof of concept i have to do for a client. So its very basic.
I have figured out how build the Silverlight3 project using RIA services etc. So passing and returning strings and int's is no problem at the moment.
But i require to return an ArrayList from my Domain Service Class to my SL3 client. But it seems passing back an ArrayList as is, is not permitted. And my limited knowledge of C# does not aid in doing quick type casting/convertions/etc. This server-side function gets an ArrayList which must be returned to the SL3 client, so i have to do something with it to send it client side.
Question:
Does anyone know what should be done to an ArrayList (in c#) to allow a DomainService class function to return it to a calling client/SL3 function?
[NOTE: the majority of my attempts all end in the error: "Service operation named 'myFunctionName' does not conform to the required signature. Both return and parameter types must be an entity type or one of the predefined serializable types."]
Please feel free to request any information you feel would be appropriate.
Thank you in advance.
My apologies for not posting the solution i found. Bosses threw more work at me than i could handle. :)
Please note my solution may not be the best but since my knowledge in SL and RIA services are so new, i guess it may be excused. Initially i wanted to pass back rather complicated arrays from the code provided by our client, but effort and time restraints allowed me to only get it right to convert and return a List.
Hope this helps in some way.
Client Side : Silverlight Code in the MainPage.xaml.cs i have a call to retrieve a list of data from the server side, to display in a dropDown list.
// Function called on load of the SL interface
// 'slayer' is an object of the Domain Service Class server-side
// 'this.gidSessionNumber' is just a number used in the demo to represent a session
public void loadPaymentTypeComboBox()
{
InvokeOperation<IEnumerable<string>> comboList = sLayer.getPaymentTypeCombo(this.gidSessionNumber);
comboList.Completed += new EventHandler(popPaymentCombo_complete);
}//function loadAllComboBoxes
// Event handler assigned
public void popPaymentCombo_complete(object sender, EventArgs e)
{
InvokeOperation<IEnumerable<string>> obj = (InvokeOperation<IEnumerable<string>>)sender;
string[] list = obj.Value.ToArray();
// 'paymentTypeDropdown' is the name of the specific comboBox in the xaml file
paymentTypeDropdown.IsEnabled = true;
// Assign the returned arrayList as itemSource to the comboBox
paymentTypeDropdown.ItemsSource = list;
}
In the Domain Service Class i have the associated function:
[ServiceOperation]
public List<string> getPaymentTypeCombo(string gidNumber)
{
// Build objects from libraries provided by our client
SDT.Life.LifeCO.clsSystemCreator.CreateSysObjects(gidNumber);
this.lobjSys = SDT.Life.LifeCO.clsSystemCreator.GetSysObject(gidNumber);
// Rtrieve the ArrayList from the client's code
clsTextList comboList= this.lobjSys.lstPaymentType_PaymentQueue;
// Get the length of the returned list
int cnt= (int)comboList.Count();
// Create the List<string> which will be populated and returned
List<string> theList= new List<string>();
// Copy each element from the clsTextList to the List<string>
for (int i = 0; i < cnt;i++)
{
string status= comboList.Item(i).Description;
theList.Add(status);
}
// return the newly populated List<string>
return theList;
}//end function getPaymentTypeCombo
Not sure that you can return an ArrayList. I guess you should think about returning an IEnumerable instead which will make the service recognize the method as a Read method.
If you have a List or ObservableCollection and wish to bind it to an ItemControl like ComboBox, you can set the ItemsSource on your ItemControl. Use the DisplayPath property on the ItemControl to set the property you wish to display or use a DataTemplate.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text={"Binding Path=Property1"}/>
<TextBlock Text={"Binding Path=Property2"}/>
<TextBlock Text={"Binding Path=Property3"}/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
How can I inject (attach) event handlers to .net events of instances created by the Unity IoC container?
Example: I have a class that reports errors via a standard .net event:
class CameraObserver
{
public event Action<Exception> UnhandledException;
[...]
}
I have another class that is reponsible for handling those events:
class CrashMonitor
{
public static void HandleException(Exception x)
{ ... }
}
What I would like to do is to automatically inject the Handler from CrashMonitor to every instance of a CameraObserver like in this pseudocode:
UnityContainer container = new UnityContainer();
container.RegisterInstance<Action<Exception>>(CrashMonitor.HandleException)
.RegisterType<CameraObserver>(new InjectionEvent(UnhandledException));
var observer = container.Resolve<CameraObserver>();
// CrashMonitor.HandleException is now attached to observer.UnhandledException
Is there a way to do this with Unity? I can think of an ugly workaround like deriving from CameraObserver with a special constructor intendend for dependency injection or or a method injection. But that would make the syste more complex (because you have to write code). I would naively expect that you could add a [Dependency] attribute on the event and everything should work.
I have asked the same question in the unity discussion group on codeplex
http://unity.codeplex.com/Thread/View.aspx?ThreadId=80728
and the answer is "there is nothing". There is a demo of an EventBroker but what it does is more complex (autowiring of publishers and subscribers). I still think a KISS mechanism to inject events is useful and started to do it by myself.