How to refresh parent screens in lightswitch? - silverlight

I want to refresh the search screens after adding new data from other screens. I've tried doing
foreach (var parentScreen in this.Application.ActiveScreens.OfType<ScreenType>())
{
//Invoke the refresh
parentScreen.Details.Dispatcher.BeginInvoke(() => parentScreen.Details.Commands.Refresh.Execute());
}
but it doesn't seem to work in Beta 2

found it on
http://social.msdn.microsoft.com/Forums/en-US/lightswitchgeneral/thread/cf86ad21-48fb-48f2-87d4-e5b15f8f361c#e6879629-145a-4b18-834c-ebee0cfe1473
Unfortunately the collection of ActiveScreens does not actually contain a set of Screen objects. It contains a proxy class that you can use to access the actual screen object (this is due to different threads running in different threads). Here is some sample code that achieves what you need.
Microsoft.LightSwitch.Client.IActiveScreen searchScreen = Application.ActiveScreens.Where(a => a.Screen is SearchCustomers).FirstOrDefault();
searchScreen.Screen.Details.Dispatcher.BeginInvoke(() =>
{
((SearchCustomers)searchScreen.Screen).Customers.Refresh();
});

Related

Why is session storage being drawn upon between different browser instances?

Background
In an application I'm working on, I've found that I can define values in sessionStorage in Chrome 62 on Windows 10, and that apparently changing that value in one tab affects other tabs that point to the same key.
I was operating under the assumption that localStorage is supposed to persist information across all browser windows, while sessionStorage is only supposed to persist information for a specific window or tab.
More specifically, I have an AngularJS service I'm using as a layer for sessionStorage interactions:
export class PersistenceSvc {
public static $inject: string[] = ['$window'];
public constructor(public $window: ng.IWindowService) {}
public save<T>(name: string, data: T): void {
const saveData: string = JSON.stringify(data);
this.$window.sessionStorage.setItem(name, saveData);
}
public load<T>(name: string): T {
const loadData: string = this.$window.sessionStorage.getItem(name);
const result: T = JSON.parse(loadData) as T;
return result;
}
}
...That I use from a run block in order to implement some data persistence in my application.
export function persistSomeData(
someSvc: Services.SomeService,
userAgentSvc: Services.UserAgentSvc,
persistenceSvc: Services.PersistenceSvc,
$window: ng.IWindowService) {
if(userAgentSvc.isMobileSafari()) {
// Special instructions for iOS devices.
return;
}
const dataToPersist: Models.DataModel = persistenceSvc.load<Models.DataModel>('SomeData');
if(dataToPersist) {
// Set up the state of someSvc with the data loaded.
} else {
// Phone home to the server to get the data needed.
}
$window.onbeforeunload = () => {
persistenceSvc.save<Models.DataModel>('SomeData', someSvc.dataState);
};
}
persistSomeData.$inject = [
// All requisite module names, omitted from example because lazy.
];
angular
.module('app')
.run(persistSomeData);
When only operating using a single tab, this works fine (unless running from an iOS device, but that's tangential to what I'm encountering.) When you do the following though, you start seeing some more interesting behavior...
Steps:
1. Open a Chrome instance. Create a new tab, and drag that out such that it becomes its own window.
2. Navigate to your site, that's using the above code.
3. Do things on your site that cause someSvc's data state to have different data in the first browser.
4. Do things on your site that cause someSvc's data state to have different data in the second browser.
5. Do something on your site that draws upon someSvc's data state in the first browser.
6. Observe that the data utilized on the first browser instance, was sourced by the second browser instance. (This is the problem, right here.)
Question:
In the past I haven't done a lot of cookie/localStorage/sessionStorage programming, so it's very possible that I've terribly misunderstood something. Bearing that in mind, why is it that window.sessionStorage is behaving in a way that the MDN documentation as well as the winning answer to this SO question says it shouldn't be behaving in?
EDIT: It turns out there is a problem, but it's not clientside. Closing this question, as I was operating under the assumption that the client was the problem.
There is something wrong with your code as a quick and easy test on the browser console shows that sessionStorage only impacts the browser tab that is open. A change in the right tab is not reflecting to the left tab:

Spring webflux data in ReactJs UI

I am playing around with spring webflux. I have created a project which would listen on a mongo capped collection and return the flux of data as and when it comes.
I am using #Tailablein my repository method.
My controller looks like this
#GetMapping("/findall")
public Flux<Product>> findAll() {
return productRepository.findAllProducts().;
}
This is working perfectly fine. I tested this by addind a doOnNext(...), Whenever there is a new item added to my capped collection, consumer inside the doOnNext is executed.
Now I want this to be displayed on the browser. And I wanted to do with ReactJs(I am completely new to frontend).
So far, I couldn't find any way to display the flux data in browser. What are the options by which I can achieve this.
I tried SSE(Server Sent Event) like this
componentDidMount() {
this.eventSource = new EventSource('http://localhost:8080/findall');
this.eventSource.addEventListener('product', (data) => {
let json = JSON.parse(data.data)
this.state.products.push(json.name)
this.setState ( {
products : this.state.products
})
});
}
This works perfectly fine, but for this to work, I had to change my server side code like this
#GetMapping("/findall")
public Flux<ServerSentEvent<Product>> findAll() {
return productRepository.findAllProducts().map(data -> ServerSentEvent.<Product>builder().event("product").data(data).build());
}
This, in my opinion is a bit tightly coupled because, UI should know the event type('product') to listen to.
Is there any other way to handle stream of events from UI side(particularly with reactjs) ?
You shouldn't have to change your controller in order to stream data to the browser. The following code snippet should work:
#GetMapping(path="/findall", produces=MediaType.TEXT_EVENT_STREAM_VALUE)
#ResponseBody
public Flux<Product>> findAll() {
return productRepository.findAllProducts();
}
You can see this feature being used in this workshop and this sample app if you'd like to see a complete working examples.

share() vs ReplaySubject: Which one, and neither works

I'm trying to implement short-term caching in my Angular service -- a bunch of sub-components get created in rapid succession, and each one has an HTTP call. I want to cache them while the page is loading, but not forever.
I've tried the following two methods, neither of which have worked. In both cases, the HTTP URL is hit once for each instance of the component that is created; I want to avoid that -- ideally, the URL would be hit once when the grid is created, then the cache expires and the next time I need to create the component it hits the URL all over again. I pulled both techniques from other threads on StackOverflow.
share() (in service)
getData(id: number): Observable<MyClass[]> {
return this._http.get(this.URL)
.map((response: Response) => <MyClass[]>response.json())
.share();
}
ReplaySubject (in service)
private replaySubject = new ReplaySubject(1, 10000);
getData(id: number): Observable<MyClass[]> {
if (this.replaySubject.observers.length) {
return this.replaySubject;
} else {
return this._http.get(this.URL)
.map((response: Response) => {
let data = <MyClass[]>response.json();
this.replaySubject.next(data);
return data;
});
}
}
Caller (in component)
ngOnInit() {
this.myService.getData(this.id)
.subscribe((resultData: MyClass[]) => {
this.data = resultData;
},
(error: any) => {
alert(error);
});
}
There's really no need to hit the URL each time the component is created -- they return the same data, and in a grid of rows that contain the component, the data will be the same. I could call it once when the grid itself is created, and pass that data into the component. But I want to avoid that, for two reasons: first, the component should be relatively self-sufficient. If I use the component elsewhere, I don't want to the parent component to have to cache data there, too. Second, I want to find a short-term caching pattern that can be applied elsewhere in the application. I'm not the only person working on this, and I want to keep the code clean.
Most importantly, if you want to make something persistent even when creating/destroying Angular components it can't be created in that component but in a service that is shared among your components.
Regarding RxJS, you usually don't have to use ReplaySubject directly and use just publishReplay(1, 10000)->refCount() instead.
The share() operator is just a shorthand for publish()->refCount() that uses Subject internally which means it doesn't replay cached values.

How to access elements of FirebaseListObservable from scripts

I am working with Angular 2 (more precisely Ionic 2) and Firebase. I use angularfire2 to make them communicate.
While I can very easily go through all the elements of a FirebaseListObservable in a view (using the pipe async syntax), I cannot find a way of doing this from within my scripts.
I've been looking for a while and there are no examples which show this way of accessing the data; they all access it from the view part of the application.
How can I access the elements of FirebaseListObservable from within scripts?
Not 100% sure what you are asking but i use
getData(fbPath:string) {
return new Promise(resolve => {
this.af.database.list(fbPath).subscribe(res => resolve(res));
})
}
In my firebase service. I can then use it in the component like so
this.api.getData('organisations').then(data => {
console.log(data);
}

My flux store gets re-instantiated on reload

Okay. I'm kinda new to react and I'm having a #1 mayor issue. Can't really find any solution out there.
I've built an app that renders a list of objects. The list comes from my mock API for now. The list of objects is stored inside a store. The store action to fetch the objects is done by the components.
My issue is when showing these objects. When a user clicks show, it renders a page with details on the object. Store-wise this means firing a getSpecific function that retrieves the object, from the store, based on an ID.
This is all fine, the store still has the objects. Until I reload the page. That is when the store gets wiped, a new instance is created (this is my guess). The store is now empty, and getting that specific object is now impossible (in my current implementation).
So, I read somewhere that this is by design. Is the solutions to:
Save the store in local storage, to keep the data?
Make the API call again and get all the objects once again?
And in case 2, when/where is this supposed to happen?
How should a store make sure it always has the expected data?
Any hints?
Some if the implementation:
//List.js
componentDidMount() {
//The fetch offers function will trigger a change event
//which will trigger the listener in componentWillMount
OfferActions.fetchOffers();
}
componentWillMount() {
//Listen for changes in the store
offerStore.addChangeListener(this.retriveOffers);
}
retrieveOffers() {
this.setState({
offers: offerStore.getAll()
});
}
.
//OfferActions.js
fetchOffers(){
let url = 'http://localhost:3001/offers';
axios.get(url).then(function (data) {
dispatch({
actionType: OfferConstants.RECIVE_OFFERS,
payload: data.data
});
});
}
.
//OfferStore.js
var _offers = [];
receiveOffers(payload) {
_offers = payload || [];
this.emitChange();
}
handleActions(action) {
switch (action.actionType) {
case OfferConstants.RECIVE_OFFERS:
{
this.receiveOffers(action.payload);
}
}
}
getAll() {
return _offers;
}
getOffer(requested_id) {
var result = this.getAll().filter(function (offer) {
return offer.id == requested_id;
});
}
.
//Show.js
componentWillMount() {
this.state = {
offer: offerStore.getOffer(this.props.params.id)
};
}
That is correct, redux stores, like any other javascript objects, do not survive a refresh. During a refresh you are resetting the memory of the browser window.
Both of your approaches would work, however I would suggest the following:
Save to local storage only information that is semi persistent such as authentication token, user first name/last name, ui settings, etc.
During app start (or component load), load any auxiliary information such as sales figures, message feeds, and offers. This information generally changes quickly and it makes little sense to cache it in local storage.
For 1. you can utilize the redux-persist middleware. It let's you save to and retrieve from your browser's local storage during app start. (This is just one of many ways to accomplish this).
For 2. your approach makes sense. Load the required data on componentWillMount asynchronously.
Furthermore, regarding being "up-to-date" with data: this entirely depends on your application needs. A few ideas to help you get started exploring your problem domain:
With each request to get offers, also send or save a time stamp. Have the application decide when a time stamp is "too old" and request again.
Implement real time communication, for example socket.io which pushes the data to the client instead of the client requesting it.
Request the data at an interval suitable to your application. You could pass along the last time you requested the information and the server could decide if there is new data available or return an empty response in which case you display the existing data.

Resources