Using class selectors to get Dojo widgets: Good or Bad? - dom

I am using Dojo 1.9 for a web application I'm writing using WebSockets. When the client receives a message from the server, I need to update certain widgets with the data received.
// sock is the client-side of the websocket
sock.onmessage = function (dataIn) {
// clientManager defined elsewhere
clientManager.fireMessageReceived(dataIn);
};
Here's my problem: At the point that I receive the data, I don't have the ID's, DOM nodes or widgets to access the properties/values to be updated. clientManager deals specifically with sock events and doesn't have any specific knowledge of the widgets that its data will be updating. Also, it's possible to have multiple instances of the same widget, so I think trying to maintain a collection of existing widgets (or ID's) as a property of the client manager could get hairy pretty quickly.
So, my solution was to use CSS classes.
I created an empty class and assigned it to my widget:
.myXYZWidget {
}
so that in my fireMessageReceived function, I can use dojo/query to find it:
var myXYZWidgets = dojo.query(".myXYZWidget");
var i;
for (i = 0; i < myXYZWidgets.length; i++) {
var xyzWidget = registry.byNode(myXYZWidgets[0]);
... // Now I have my Dojo widget, I can upate to my heart's content
}
This works and I'm not seeing any major downsides to doing this, but is this ok or is this bad bad bad? Can anyone in the community that has a knowledge of Dojo confirm this solution or suggest a better one?

A class is not necessarily CSS. So you're not using CSS to get Dojo widgets, you're just accessing the widgets by a selector/query.
If I think about your problem I would think about the publisher/subscriber pattern where your websocket is your publisher (since it receives data and needs to emit it to your widgets) and your widgets are your subscribers.
Subscriber(s) (widgets)
Luckily for you dojo has something for it and it's called the dojo/topic module. When you create your widget, you somehow want to make sure that it's a subscriber of the data your websocket receives. To do that, I would do something like this (I'm using a dijit/form/Select in my example, but you can rewrite it to whatever you want):
lang.mixin(mySelect, {
__getData: function(data) {
this.addOption(data);
}
});
mySelect.own(topic.subscribe("my/event", lang.hitch(mySelect, '__getData')));
What happens here is pretty easy (altough it might look hard). The first thing I do is to make sure my widget has an extra method called __getData. This method will receive the data from the websocket and will update its own based on the data.
Then I make sure the widget is subscribed to events with the name my/event (you will see what this means in a while).
Publisher (websocket)
Then at the level of your websocket code, you want to publish to a topic called my/event so that your widgets will know about it.
You can do that like this:
topic.publish("my/event", myData);
Where myData is the data you received from your websocket.
So now the flow is complete. Your websocket code will emit data to who wants to listen. The listeners (widgets) will use the data and do something with it, for example adding items to themself.
I also made a JSFiddle showing a complete example. This solution might look more complex, but I think it's pragmatically more correct.

Related

Project Reactor and Server Side Events

I'm looking for a solution that will have the backend publish an event to the frontend as soon as a modification is done on the server side. To be more concise I want to emit a new List of objects as soon as one item is modified.
I've tried implementing on a SpringBoot project, that uses Reactive Web, MongoDB which has a #Tailable cursor that publish an event as soon as the capped collection is modified. The problem is that the capped collection has some limitation and is not really compatible with what I want to do. The thing is I cannot update an existing element if the new one has a different size(as I understood this is illegal because you cannot make a rollback).
I honestly don't even know if it's doable, but maybe I'm lucky and I'll run into a rocket scientist right here that will prove otherwise.
Thanks in advance!!
*** EDIT:
Sorry for the vague question. Yes I'm more focused on the HOW, using the Spring Reactive framework.
When I had a similar need - to inform frontend that something is done on the backend side - I have used a message queue.
I have published a message to the queue from the backend and the frontend consumed the message.
But I am not sure if that is what you're looking for.
if you are using webflux with spring reactor, I think you can simply have a client request with content-type as 'text/event-stream' or 'application/stream+json' and You shall have API that can produce those content-type. This gives you SSE model without too much effort.
#GetMapping(value = "/stream", produces = {MediaType.TEXT_EVENT_STREAM_VALUE, MediaType.APPLICATION_STREAM_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public Flux<Message> get(HttpServletRequest request) {
Just as an idea - maybe you need to use a web socket technology here:
The frontend side (I assume its a client side application that runs in a browser, written in react, angular or something like that) can establish a web-socket communication with the backend server.
When the process on backend finishes, the message from backend to frontend can be sent.
You can do emitting changes by hand. For example:
endpoint:
public final Sinks.Many<SimpleInfoEvent> infoEventSink = Sinks.many().multicast().onBackpressureBuffer();
#RequestMapping(path = "/sseApproach", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<SimpleInfoEvent>> sse() {
return infoEventSink.asFlux()
.map(e -> ServerSentEvent.builder(e)
.id(counter.incrementAndGet() + "")
.event(e.getClass().getName())
.build());
}
Code anywhere for emitting data:
infoEventSink.tryEmitNext(new SimpleInfoEvent("any custom event"));
Watch out of threads and things like "subscribeOn", "publishOn", but basically (when not using any third party code), this should work good enough.

(React/redux) Using Sockets with redux to only send changed pieces of state

I'm trying to figure out how to use socket.io alongside of my react/redux application, and seeing how much I can optimize when doing so. So, on the server I have a pretty basic setup with the sockets you can see here :
store.subscribe(() => {
io.emit('state', store.getState().toJS());
});
io.on('connection', (socket) => {
socket.emit('state', store.getState().toJS());
socket.on('action', function (action) {
action.headers = socket.request.headers;
store.dispatch(action);
});
});
So the only thing out of the ordinary is I was just sticking the request headers onto the actions for use later. What I would like to try and achieve is something like this -
io.connections[i].emit('state')
and add
socket.on('state', (action) => {
socket.emit('state', getUserSpecificState(store));
});
The idea is this would allow me to loop through all the connections, and then use that connection's socket to call for the specific user at the time. I don't know if something like this is possible, and am looking for some possible feedback in handling sending back only user specific information back. It would also be cool to only send back the part of the state changed by the action (and not the whole state), and then have the front end store assemble the state. Any/all input is more than welcomed, thanks!
Looks like it's not redux's issue to handle this logic, you put it in some module and connect to state using middleware or just by using state object "from the outside". Speaking of state management, what are you trying to implement? Looks like case for some CRDT thing like swarm.js or diffsync.

Creating a REST service in Sitecore

I'm trying to build a REST service in a Sitecore root. My application start looks like this:
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = System.Web.Http.RouteParameter.Optional });
}
And my URL looks like this:
http://{mydomain}/api/books
I have the correct controller and all that.
But Sitecore keeps redirecting me to the 404 page. I've added the path to the IgnoreUrlPrefixes node in the web.config, but to no avail. If I had to guess, I'd think that Sitecore's handler is redirecting before my code gets the chance to execute, but I really don't know.
Does anybody have any idea what might be wrong?
Your assessment is correct. You need a processor in the httpRequestBegin pipeline to abort Sitecore's processing. See the SystemWebRoutingResolver in this answer:
Sitecore and ASP.net MVC
It's also described in this article:
http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2010/10/Sitecore-MVC-Crash-Course.aspx
But I'll include the code here as well. :)
public class SystemWebRoutingResolver : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
RouteData routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(args.Context));
if (routeData != null)
{
args.AbortPipeline();
}
}
}
Then in your httpRequestBegin configuration:
<processor type="My.SystemWebRoutingResolver, My.Classes" />
You might want to have a look at Sitecore Web Api
It's pretty much the same you are building.
Another option, which I've used to good effect, is to use the content tree, the "star" item, and a sublayout/layout combination dedicated to this purpose:
[siteroot]/API/*/*/*/*/*/*/*/*/*
The above path allows you to have anywhere between 1 and 9 segments - if you need more than that, you probably need to rethink your process, IMO. This also retains all of the Sitecore context. Sitecore, when unable to find an item in a folder, attempts to look for the catch-all star item and if present, it renders that item instead of returning a 404.
There are a few ways to go about doing the restful methods and the sublayout (or sublayouts if you want to segregate them by depth to simplify parsing).
You can choose to follow the general "standard" and use GET, PUT, and POST calls to interact with these items, but then you can't use Sitecore Caching without custom backend caching code). Alternately, you can split your API into three different trees:
[siteroot]/API/GET/*/*/*/*/*/*/*/*/*
[siteroot]/API/PUT/*/*/*/*/*/*/*/*/*
[siteroot]/API/POST/*/*/*/*/*/*/*/*/*
This allows caching the GET requests (since GET requests should only retrieve data, not update it). Be sure to use the proper caching scheme, essentially this should cache based on every permutation of the data, user, etc., if you intend to use this in any of those contexts.
If you are going to create multiple sublayouts, I recommend creating a base class that handles general methods for GET, PUT, and POST, and then use those classes as the base for your sublayouts.
In your sublayouts, you simply get the Request object, get the path (and query if you're using queries), split it, and perform your switch case logic just as you would with standard routing. For PUT, use Response.ReadBinary(). For POST use the Request.Form object to get all of the form elements and iterate through them to process the information provided (it may be easiest to put all of your form data into a single JSON object, encapsulated as a string (so .NET sees it as a string and therefore one single property) and then you only have one element in the post to deserialize depending on the POST path the user specified.
Complicated? Yes. Works? Yes. Recommended? Well... if you're in a shared environment (multiple sites) and you don't want this processing happening for EVERY site in the pipeline processor, then this solution works. If you have access to using MVC with Sitecore or have no issues altering the pipeline processor, then that is likely more efficient.
One benefit to the content based method is that the context lifecycle is exactly the same as a standard Sitecore page (logins, etc.), so you've got all the same controls as any other item would provide at that point in the lifecycle. The negative to this is that you have to deal with the entire page lifecycle load before it gets to your code... the pipeline processor can skip a lot of Sitecore's process and just get the data you need directly, making it faster.
you need to have a Pipeline initializer for Routing:
It will be like :
public class Initializer
{
public void Process(PipelineArgs args)
{
RouteCollection route = RouteTable.Routes;
route.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
}
}
On config file you will have :
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor type="_YourNameSpace.Initializer,_YourAssembly" />
</initialize>
</pipelines>
</sitecore>
</configuration>
Happy coding

remote pupulation of GWT listbox

I am trying to use RPC calls for fetching data from the Server-->DB and then populate my client side widgets like ListBox, Grid etc. The problem is that since the calls are asynchronous, it cannot be guaranteed that the client side runtime will wait for the server calls to come back and then populate the widgets using the data from the callback result. Is there a way to do this?
regards,
J
By design, there is no way to make a synchronous request in GWT. You can, however refrain from showing the widgets (and perhaps display a spinner) until the data has returned from the server. A way to do this would be to make the widgets visible in a method that is called from the AsyncCallback you used when getting the data from the server.
An example follows (in practice, you'd probably do this at a form level, as opposed to a widget level, but you get the idea).
AsyncCallback<List<Option>> callback = new AsyncCallback<List<Option>>() {
public void onFailure(Throwable caught) {
processError(caught);
}
public void onSuccess(List<Option> result) {
updateListBox(result);
showListBox();
}
};
myRemoteService.getOptions(callback);
You may display a modal dialog box (with a message like "fetching data", or anything fancier), when you start fetching data, and then you may close the dialog box when your RPC call terminates. Another approach is to use a small loading panel that you activate/de-activate as needed: an example is here

Send a empty Message or Notification with MVVM toolkit light

I'm using the MVVM Light Toolkit. I could not find any Ctor of Messenger or Notification class to send a empty message.
ViewModel1:
private int _selectedWeeklyRotation;
public int SelectedWeeklyRotation
{
get { return _selectedWeeklyRotation; }
set
{
if(_selectedWeeklyRotation == value)
return;
_selectedWeeklyRotation = value;
this.OnPropertyChanged("SelectedWeeklyRotation");
if(value > 1)
Messenger.Default.Send();
}
}
ViewModel2:
Ctor:
Messenger.Default.Register(this, CreateAnotherTimeTable);
private void CreateAnotherTimeTable()
{
}
I just need to send a Notification to another ViewModel, no sending of data at all.
Is that possible with MVVM Light Toolkit library?
Unless I'm misunderstanding something, couldn't you accomplish this by creating and sending a custom "signal message" type via the Messenger?
public class WeeklyRotationSignal {}
Messenger.Default.Send(new WeeklyRotationSignal());
Then register to that in another view model:
Messenger.Default.Register<WeeklyRotationSignal>(this, msg => doWork);
You can try sending a simple message with a string tag and receive that message by matching the string tag. Something like this:
Sender portion of the code located possibly in something like ViewModel1.cs
Messenger.Default.Send<string>("Dummy text message", "String_ToHelpMatchTheMsg");
Receiving end portion of the code responding to that message above, possibly located in some other file, something like ViewModel2.cs
...
Messenger.Default.Register<string>(this, "String_ToHelpMatchTheMsg", executeThisFunction);
private void executeThisFunction(string strMsg)
{
//your code would go here to run upon receiving the message
// The following line will display: "Dummy text message"
System.Windows.Browser.HtmlPage.Window.Alert("msg passed: " + strMsg);
}
Please note that you dont have to do anything with the text message that is passed around with the messaging code above. Just one part of the code sending some ping to another part of the code to ask some other section to execute some code. The important string is the one where I used "String_ToHelpMatchTheMsg" because that is the key used to match the sender and the receiver. Almost like creating your own quasi-event, once the Send method runs, the Register method is notified and fire its own function to run also.
I used this with a Close button on a Child Window to close it. The Close button on the View of the Child Window binds to a relay command on its childWindowViewModel. That relay command has the code above to send a message to the ParentViewModel. The Register portion on the ParentViewModel responds to that message by firing a method that closes the ChildWindow which was initially instantied from that parentViewModel.
Once you get more familiar with messaging, there are more attributes that you will be able to use so that the receiver can call back the sender to give a status or some data back. Look for Delegates and lambda function to achieve this.
All this to avoid placing code in the code behind to close the child window! :-)
Use as you see fit.
Cheers.
Mario
There really isn't a way to accomplish this and in someways defies the point of the messenger class. I didn't want to write a your doing it wrong post, but I feel I am stuck. The way the messenger class works is that you have two parties that both subscribe to the same concept, its an observer model. Without that similar concept or message there really isn't a way to tie the two objects together. The generic message whether a simple string or custom message act as the meeting point of the Subscribing and Publishing classes.
If the ViewModel publishing knows the type of ViewModel its trying to Send to it could...
Messenger.Default.Send<Type>(typeof(ViewModelToSendTo);
This would act as a very simple interaction point, you also wouldn't have to create a custom class. Some purist may have an issue with this approach as it couples the publishing class to the subscriber.
I don't think that it is possible and frankly I don't see the point of having that kind of message. You could just as well send a string "SelectedWeeklyRotation". It seems strange to have an empty message that has some kind of meaning as you increase the number of broadcast messages - and receivers in your application.
In the version of MVVM Light that I'm using it is not even possible to send an empty message.
However I did see a method in the ViewModelBase that is :
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
This might be of interest for you.