Angular 2 events get postponed strangely when I include some other non-angular script - events

I have encountered a strange problem when using angular 2 beta RC.
Events get postponed if I include an external script I wrote into any angular 2 project:
<script>
(function(r,a,k,e,y,o,u){r['RakrWidgetObject']=y;r[y]=r[y]||function(){
(r[y].q=r[y].q||[]).push(arguments)},r[y].l=1*new Date();o=a.createElement(k),
u=a.getElementsByTagName(k)[0];o.async=1;o.src=e;u.parentNode.insertBefore(o,u)
})(window,document,'script','//cht.technology/rakr.js','rakr');
rakr('//localhost:3000', 'RAKR-000001');
</script>
Take github project thelgevold/angular-2-samples for example, once I add the below script as I did in https://github.com/tan9/angular-2-samples/tree/event-postponed branch.
The angular 2 application starts to behave strangely, some event changes won't be taking into account by angular until I trigger another event manually, I have to click a button twice to get correct rendering as this recording I uploaded to imgur
I don't know what's happening to the external script I wrote, it's a simple project that only depends on html2canvas and es6-promise, which can capture screenshot using html2canvas and send it to another web service. The bundle was built by webpack, and I tried to build the bundle by using browersify, with no luck.

This is a caveat with how Zone.js works. Zone.js patches async browser events and provides an API in which Angular uses to determine when changes happen and when to run change detection in order to update the UI.
In the case of your third-party library that uses the browser Promise API, it needs to be loaded before Zone.js is loaded via script tag. This is so that async events are patched so it will be run in the "zone" that Angular runs in. Events running outside the zone won't be picked up unless change detection is run manually, or the event is run in the context of the Angular zone.

As explained by brandon, make the code run inside Angulars zone
inject NgZone
constructor(private ngZone:NgZone){}
...
this.zone.run(() => ... /* code here that modifies Angulars model from the outside */);
You can also get the zone outside Angular
bootstrap(AppComponent, ...).then((ref => ref.instance.injector.get(NgZone));
(Not sure if this is 100% correct, I'm just on my phone and looking up is cumbersome. Please post a comment if you can't make it work.

Related

How to change URL at runtime

We are trying to use Cobalt (20.stable) browser as the browser of our web SPA application.
My requirement is to be able to change URL at runtime, what I was able to find in the code:
Is:
starboard::shared::starboard::Application::Link(const char* link_data)
which ends up sending:
kSbEventTypeLink
Unfortunately this is not working, as code is ignoring the call; the handling reaches the point:
// TODO: Remove this when terminal application states are properly handled.
if (deep_link_event->IsH5vccLink()) {
browser_module_->Navigate(GURL(deep_link_event->link()));
}
In my case I m trying to change the URL to let say https://www.example.com.
There should be a way to do that as when navigating we can always have a link that will cause the browser to go to some URL?
Porting layer is not supposed to control navigation directly. Instead, your Starboard implementation may send a deep link event which could be intercepted by a web app which will perform a navigation. See h5vcc_runtime.idl for Web API.
That said, if you are building an SPA, why do you even need to change a URL? Initial URL of a web app is controlled by --url command line switch.
When you say runtime are you looking to change the initial URL when the app is first launched? If so, you could just use the --url parameter.
So you could do the following:
cobalt --url="https://www.example.com"
I did a patch to allow changing the URL.
I just need to call starboard::shared::starboard::Application::Link("https://www.example.com").
Inside this call a DeepLinkEvent is posted.
Patch : https://gofile.io/?c=9GvNHX
Cobalt does not navigate for you. The JavaScript receives the deeplink with the function it sets on h5vcc.runtime.onDeepLink and then does whatever it wants with that. As a SPA, it will parse the URL and load new content from its server in its own internal data format (e.g. protocol buffers, JSON, etc.) which it uses to update its own DOM to show new content.
Navigating is not the point of a SPA since that makes it not be a single page application. However, there may be cases such as a loader app that will want to make some initial decisions then load the actual SPA. That loader app would have to have the appropriate CSP rules in place, then set window.location to the URL of the page to navigate to.
Note: The code you found in Application::OnDeepLinkEvent() is a remnant that previously supported the H5vccURLHandler, which was removed in Cobalt 20. It's not meant to navigate to arbitrary deeplinks.

Nativescript - resumeEvent handling

In my app when the app is resumed from a sleep, I'd like to
reload the page - or ideally, just update specific UI elements.
How can this be done?
Preferably in a platform independent way.
You want to hook into the onResume method in the application module which exposes the event when an app resumes from the background.
https://docs.nativescript.org/api-reference/modules/application.html#onresume
So in your app.js (the entry point of your application), import the module and add the onResume event handler and it can run everytime the app resumes. Now reloading a page will require a little more work. You'd have to use the frame module and find out the current page and do your work, but I'm guessing it can be done with a little effort using the approach mentioned.
UPDATE: based off your comment, you need the reloadPage() method from the ui/frame module. https://docs.nativescript.org/api-reference/modules/_ui_frame_.html#reloadpage
The correct method is reloadPage() in the Frame module (as contributed by #Brad) but the problem is that it's NOT an exposed api.
No problem - just copy/paste it and it works.
The problem is that it basically does a navigateTo() to the currentPage and that effects the navigation history. You have 2 choices - setting clearHistory to true and you lose all history (don't want that) or set clearHistory to false which creates a a duplicate of the current-page (don't want that either). There's also a backstackVisible option but that doesn't help in this scenario.
#Brad tells me that there's api that allows access to the navigation stack - haven't looked into it.
For my app - the user will be at the root page most of the time, so I decided to reload the page only if on the root page and then set clearHistory to true and that works for me.

Bootstrap ui-router states programmatically

I'm working with angular 1.
I want to load some data from server before ui-router bootstrapping all the states.
Is it possible to do so?
I would say that in this Question: AngularJS - UI-router - How to configure dynamic views and mostly in this answer you can get the answer.
The point is to use a feature of UrlRouterProvider - deferIntercept()
The deferIntercept(defer)
Disables (or enables) deferring location change interception.
If you wish to customize the behavior of syncing the URL (for example,
if you wish to defer a transition but maintain the current URL), call
this method at configuration time. Then, at run time, call
$urlRouter.listen() after you have configured your own
$locationChangeSuccess event handler.
Full description including working example is here

How to call a Javascript function inside an webview on nativescript?

How to call a Javascript function (and register a callback function to be executed after the method execution from web view is done) inside an webview on nativescript?
First the bad new, nothing is "built" in to do this. This requires you to add some code to communicate back from the webview. In the nativescript-webworkers plugins that I wrote; the way I did it was I used the onJsConfirm function on Android. On iOS I used the userContentControllerDidReceiveScriptMessage callback to communicate back. If you want to develop your own code; just grab a copy of my webworkers plugin and you can see the way to do it.
Now to the good news, is that it appears there is already a plugin called "nativescript-webview-interface" which gives you this facility so you don't have to build all that binding code yourself. It looks like all you need to do is include it and you will have bi-directional communications with your webview on both iOS and Android.
Note; to see if a plugin exists in the NativeScript community; your best bet is to look on http://plugins.nativescript.rocks, that is how I found out about the above listed plugin.

Modify webpage on Share Extension iOS8

I try to run js pre/post processor to modify webpage after finish share extension, but finalize method failed to run.
In Apple document it said that both Share extensions and Action extensions can benefit from this js processor, but my finalize method not get called. Only run method get called. Anyone know how to make this work ?
Accessing a Webpage
In Share extensions (on both platforms) and Action extensions (iOS
only), you can give users access to web content by asking Safari to
run a JavaScript file and return the results to the extension ...
https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html
Here is sample project: https://app.box.com/s/9ild73l9gbmfazrmjerk
In your code you have a typo in function type, should be "finalize" instead of "finalizea".

Resources