Windows.UI.WebUI.WebUIApplication versus WinJS.Application - events

What is the distinction between Windows.UI.WebUI.WebUIApplication versus WinJS.Application?
WinJS.Application is a namespace. WebUIApplication is an object (or a class of object). But consider the following:
WebUIApplication supports the following events:
WebUIApplication.activated
WebUIApplication.resuming
WebUIApplication.suspending
WebUIApplication.navigated
WinJS.Application Namespace defines the following events:
onactivated
oncheckpoint
onerror
onloaded
onready
onsettings
onunload
In particular, why is resuming done with WebUIApplication but not with WinJS.Application, but it seems that activation and checkpoint can be done either way?
Windows.UI.WebUI.WebUIApplication.onresuming = function (args) { ... }; // OK
WinJS.Application.oncheckpoint = function (args) { ... }; // OK
WinJS.Application.onactivated = function (args) { ... }; // OK
WinJS.Application.onresuming = function (args) { ... }; // NOT OK

The APIs you refer to that are in the Windows.* namespace are the actual core of the app model. Everything in WinJS, on the other hand, are wrappers that are intended to simplify that app model where there is value in doing so. For example, most apps need to do some work on the suspending event, and WinJS provides a sessionState object that is automatically saved on suspended and reloaded when the app is relaunched. However, because there's typically no action that WinJS needs to do for resuming, it doesn't wrap that particular event.
The Windows.* (WinRT) APIs, in other words, are the essential core that you have to use to write an app. WinJS is an optional library that is not at all required, but contains many essentials (like controls) that most apps will use anyway.
Typically, then, you'll use the WinJS events for convenience. It's also easy to include resuming in this model: add a handler for the WebUIApplication.oneresuming event, and call WinJS.Application.queueEvent("resuming", ...) which will then route a "resuming" event into the WinJS.Application object. That way you can centralize your handling of application events in one place.
I talk more of the relationship between these in Chapter 3 of my free ebook, Programming Windows Store Apps in HTML, CSS, and JavaScript, Second Edition, currently in preview. See http://aka.ms/BrockschmidtBook2.

Related

How can I call a back-end service function from the Success function of the MainCell in the front-end in a JAMstack RedwoodJS app?

I'm using RedwoodJS.
My front-end (what they call the "web" "side") has (among other files) a HomePage.ts and MainCell.ts, and then the Success function in MainCell calls a 3rd party API.
Everything is working.
However, I now want to start caching the results from the 3rd party API.
I've created a database table and a back-end "service" called cachedQueries.ts (using Prisma), which has:
export async function getFromCacheOrFresh(key: string, getFresh: Function, expiresInSec: number): Promise<any> {
const nowMoment = dayjs.utc();
const nowStr = nowMoment.format(dbTimeFormatUtc);
const cached = await getCachedQuery({ key, expiresAtCutoff: nowStr });
console.log('getFromCacheOrFresh cached', cached);
if (cached) {
const cachedValueParsed = JSON.parse(cached.value);
console.log('cachedValueParsed', cachedValueParsed);
return cachedValueParsed;
} else {
const fresh = await getFresh();
saveToCache(key, JSON.stringify(fresh), expiresInSec);
return fresh;
}
}
I have proven that this cachedQueries.ts service works and properly saves to and retrieves from the DB. I.e. for any 3rd-party APIs that can be called from the back-end (instead of from the front-end), the flow all works well.
Now my challenge is to enable it to cache front-end 3rd-party API queries too.
How I can call my getFromCacheOrFresh function from the Success function of the MainCell in the front-end?
I must be confused about Apollo, GraphQL, RedwoodJS, Prisma, etc relate to each other.
P.S. Client-side caching will not suffice. I really need the 3rd-party API results to be saved in the DB on my server.
I eventually figured it out.
I created a new cell called GeoCell, and I'm returning an empty string for each function of GeoCell (Success, Loading, Empty, and Failure).
That feels weird but works.
What was unintuitive to me was the idea that I was required to use a JSX component (since Apollo would never let me query or mutate GraphQL outside of a JSX component), but I didn’t want the cell component to actually display anything… because all that it needs to do in its Success is call a helper function that affects elements aleady created by a different cell (i.e. addMarkerAndInfoWindow affects the div of the existing Google Map but doesn’t display anything where the GeoCell was actually located).
As https://stackoverflow.com/a/65373314/470749 mentions, there's a related discussion on the Redwood Community Forum: Thinking about patterns for services, GraphQL, Apollo, cells, etc.

How to overwrite global event handler in nested Vue component, and later use the previous one?

I am working in Vue and also i use VueRouter, VueX and VueWebsocket. My App has component called App which holds all other components inside itself. Also I have websocket event which is set globally like this:
this.$options.sockets.onmessage = (websocket) => { /* sth1 */ }
When it gets any data from websocket, sth1 is called. it works like charm. However deep inside App component is another component, let's call it InputComponent. It may be included in App or not becaue it is single page aplication and some parts do include InputComponent, and some do not. Inside InputComponent there is also:
this.$options.sockets.onmessage = (websocket) => { /* sth2 */ }
And of course it overwrites function on message so sth1 will never be executed if InputComponent is nested by App component. It is quite obvious. However if i remove (in next SPA page), and InputComponent disappears i still have my onmessage event overwritten which i would like to have in original version.
I could ofcourse make some kind of merging functionalities of sth1 and sth2 in App component or InputComponent but it is repeating myself.
Here comes the question - is there a way to return original version of onmessage event without reloading whole App Component? In other words: can i have temporary overwritten function and then come back to its functionalities? Something like extending an eent with new functionalities of sth2.
I hope you get the idea!
K.
The general way to do that would be to use addEventListener and removeEventListener. So in the input component
created() {
this.$options.sockets.addEventListener('message', handleMessage);
},
destroyed() {
this.$options.sockets.removeEventListener('message', handleMessage);
}
Note that this approach doesn't prevent the original handler from also receiving the events. Without knowing more about the app architecture, it's hard to suggest the best way to avoid this behavior, but perhaps you can set a messageHandled flag on the event in the component's handler; then check that flag in the parent.

What is the best place to put onEnter, onExit callback functionality?

I am creating my first project that uses ui-router.
My project has about 10 views, each with their own controller and state. I am trying to modularise/encapsulate/decouple as best as possible but I am having trouble working out where to put the onExit and onEnter state callbacks.
The first option is to put it in app.js which is currently defining all of my states, however I feel that this would not be a good place as it could cause this file to blow up and become hard to read as more states are introduced and the logic gets more complex.
The second option I looked into was to put it into a controller (I have one for each state), however from researching it doesn't seem to be best practice to do this.
The third option is to create a service that is resolved, however with this option I would end up with either a giant service full of state change functions for each of the states (not decoupled) or an additional service per state which would contain the state change functionality, and I worry that would increase project complexity.
What is the standard way to achieve this?
Are there any other options that I am missing?
Our strategy for this has been to disregard the onEnter and onExit on the state object, because as you are discovering, they feel like they are in the wrong place in terms of separation of concerns (app.js).
For onEnter: we handle setup in an activate() function in each controller, which we manually execute inside the controller. This happens to also match the callback that will get executed in Angular 2.0, which was not an accident ;).
function activate() {
// your setup code here
}
// execute it. this line can be removed in Angular 2.0
activate();
For onExit: We rarely need an exit callback, but when we do, we listen for the $scope $destroy event.
$scope.$on("$destroy", function() {
if (timer) {
$timeout.cancel(timer);
}
});

What's the difference between relying on Application's event mixin and Application.vent?

What's the point of Application.vent in Marionette? The Application object already extends Backbone.Events, so I can write the following:
window.app = new Backbone.Marionette.Application();
app.on("my:event", function() { console.log(arguments); });
app.trigger("my:event");
More easily than:
window.app = new Backbone.Marionette.Application();
app.vent.on("my:event", function() { console.log(arguments); });
app.vent.trigger("my:event");
I've read the source and I can't tell the difference, but that doesn't mean there isn't one, and I'm half-willing to bet there's a good reason it's done the way it is.
While Application.vent's functionality does overlap Application's built-in events, it adds more functionality than just a simple on/trigger event mechanism because it's an instance of Backbone.Wreqr. This adds command events and a request/response mechanism to allow modules to communicate to each other more easily.
It's still just events at the heart of it, but it aims to make inter-module communication a little easier to follow.

Prism 2.1 Publish/Subscribe with weak reference?

I am building a Prism 2.1 demo by way of getting up to speed with the technology. I am having a problem with CompositePresentationEvents published and subscribed via the Event Aggregation service. The event subscription works fine if I set a strong reference (KeepSubscriberReferenceAlive = true), but it fails if I set a weak reference (KeepSubscriberReferenceAlive omitted).
I would like to subscribe with a weak reference, so that I don't have to manage unsubscribing from the event. Is there any way to do that? Why is a strong reference required here? Thanks for your help!
Here are the particulars: My demo app is single-threaded and has two regions, Navigator and Workspace, and three modules, NavigatorModule, WorkspaceAModule, and WorkspaceBModule. The NavigatorModule has two buttons, 'Show Workspace A' and 'Show Workspace B'. When one of these buttons is clicked, an ICommand is invoked that publishes a CompositePresentationEvent called ViewRequested. The event carries a string payload that specifies which workspace module should be shown.
Here is the event declaration, from the app's Infrastructure project:
using Microsoft.Practices.Composite.Presentation.Events;
namespace Prism2Demo.Common.Events
{
public class ViewRequestedEvent : CompositePresentationEvent<string>
{
}
}
Here is the event publishing code, from the Navigator module:
// Publish ViewRequestedEvent
var eventAggregator = viewModel.Container.Resolve<IEventAggregator>();
var viewRequestedEvent = eventAggregator.GetEvent<ViewRequestedEvent>();
viewRequestedEvent.Publish(workspaceName);
Here is the event subscription code, which each Workspace module includes in its Initialize() method:
// Subscribe to ViewRequestedEvent
var eventAggregator = m_Container.Resolve<IEventAggregator>();
var viewRequestedEvent = eventAggregator.GetEvent<ViewRequestedEvent>();
viewRequestedEvent.Subscribe(this.ViewRequestedEventHandler, ThreadOption.PublisherThread, true);
The Subscribe() statement is shown with a strong reference.
Thanks again for your help.
A couple of things to check:
Make sure that your EventAggregator instance is being correctly registered with the container or it may itself be garbage collected:
container.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());
Also make sure that you have a strong reference to the subscribed object held somewhere (this in your subscription code).

Resources