Using SailsJS sails.io with Angular 2 - javascript

Is there a way to instantiate sails.io inside the zone of a service provider in Angular2 so that websocket events trigger change detection?
A sub-question: how to RXJS to subscribe to sails.io data streams.
I'm using Angular2 RC4, and the latest version of SailsJS.
Related question: Angular2 View Not Changing After Data Is Updated

UPDATE
It annoyed me that I couldn't give a full example of how to use Sails with Angular 2 with just plunker, so I created a github repo, that provides the full picture on how this can work.
I can see how the related question you linked, would lead you down the zone path. However, you can plug all of this together without having to manually tinker with zones. Here is an example of how you could implement sails.io with Angular2 in a plunker. This leverages using RxJS to create a type of observable. You also have to implement a different version of Angular2 change detection(all of this is implemented in the plunker).
I go into a little more detail in my answer to your linked question.
As for your sub question I'm not sure if there is a way to integrate the stream, I believe one of the intentions of RxJS was to reduce the use of callbacks, which sails.io appears to still do.
Excerpt of implementing sails.io in a service from the plunker.
constructor() {
this._ioMessage$ = <Subject<{}>>new Subject();
//self is the window object in the browser, the 'io' object is actually on global scope
self.io.sails.connect('https://localhost:1337');//This fails as no sails server is listening and plunker requires https
this.listenForIOSubmission();
}
get ioMessage$(){
return this._ioMessage$.asObservable();
}
private listenForIOSubmission():void{
if(self.io.socket){//since the connect method failed in the constructor the socket object doesn't exist
//if there is a need to call emit or any other steps to prep Sails on node.js, do it here.
self.io.socket.on('success', (data) => {//guessing 'success' would be the eventIdentity
//note - you data object coming back from node.js, won't look like what I am using in this example, you should adjust your code to reflect that.
this._ioMessage$.next(data);//now IO is setup to submit data to the subscribbables of the observer
});
}
}

Related

Get access to Angular service instance from JavaScript code

What I'm trying to do is have some testing assertions based on the data in the Angular service, i.e. we're trying to create E2E tests and the tool we're using allows us to execute arbitrary JavaScript code for assertions, so for that I need to know if it's possible to get access to the Angular service instance.
How can I get access to an Angular service instance from plain JS code?
That is, if my Angular app is deployed, and I open the app in the browser, then open Chrome DevTools, can I get access to the service instance of the my Angular service that was provided to all components?
I know it's possible to get access to your component by through ng.probe($0) etc. but not sure about services.
From what I have searched so far, it seems like we have to do use the Injector class and then use it's .get() method to get access to one of the Angular service instances but I'm not sure how would I get access to the Injector class/instance itself?
Here's what I tried: ng.probe($0) ($0 being the <app-root> of my app) and then I see that the return value has an .injector property, I tried to call ng.probe($0).injector.get('MyServiceName') and got an error for: Uncaught Error: No provider for MyServiceName!.
(Even though I'm trying ng.probe above, I would love to know how to get access to the injector without ng.probe because during execution of the automated testing i.e. prod mode, I don't think I'll be able to do ng.probe($0))
So I'm not sure if I'm trying to access it the right way? Any ideas?
I'm using Angular 4.
This works for me in Angular 7 using ng.probe():
window.ng.probe(window.getAllAngularRootElements()[0])
.injector.view.root.ngModule._providers
.find(p => p && p.constructor && p.constructor.name === 'MyServiceName');
And I guess it is not possible to do it another way without ng.probe()

Call Electron method from Frontend

I'm trying to figure out how to call an Electron method from my frontend application javascript. Either the main or renderer process would do fine for starters, presumably I can work through the rest from there.
In all the examples I can find, the renderer code attaches to the frontend element and adds an event listener:
document.querySelector('#btn').addEventListener(() => { // doElectronStuff });
This is not quite what I'm after though... it seems like a rather severe coupling to have this "server side" code reaching into my DOM.
Using an Angular2 frontend, I found what appears to be a nice package called ngx-electron which exposes the electron interface as an injectable complete with typescript mappings, etc.
So now I have an Angular service that I want to call an Electron method for (to grab some database stuff, or whatever else):
constructor(private _electron:ElectronService) {}
getAll(): Entity[] {
var results = this._electron.ipcRenderer.?????
}
I really have no idea how to make the angular service make that call to the electron method. I've tried running emit() and have tried using send() and such against the ipcRenderer, the remote.ipcMain, but receive various errors and all and all can't seem to make the connection.
Hopefully I missing something simple? What's the combination of electron-side syntax and angular-side syntax that's required to match these up? Thanks
(I'm not particularly stuck on ngx-electron, but it did seem a nice lib and I'm assuming it works well, once I get past my own block...)
Found it. As usual, an oversight on my end.
// in the angular service
this._electron.ipcRenderer.send('event-aka-channel-name1', args);
// in the electron main.js
ipc.on('event-aka-channel-name1', (event, args) => { // doStuff });
My issue was apparently a misspelling of an import which I caught via various logs. Once that was fixed the rest works as intended (or at least enough for me to move forward)

Iron Router vs Flow Router

I am asking this question because I am a bit confused. I just started to discover meteor ( better late then never ) and I am reading/hearing a lot of discussions why I should use Flow-router instead of Iron router.
I started my project with Iron router, but the more I read the more I think I should switch to Flow-router for many performances, rendering reasons ...
What pro's and con's make them different?
Sank U !
The official documentation recommends FlowRouter: https://guide.meteor.com/routing.html
But you can use iron router too. I have already used them both in different projects, but I decided to follow meteor official recommendation.
I use IronRouter, because the description states that
"FlowRouter only deals with registration of subscriptions. It does not
wait until subscription becomes ready."
(https://github.com/kadirahq/flow-router)
Because of this, when you subscribe to large data, you get extra page updates or failures. So I chosed IronRouter, which in the documentation describes how to make the waiting for the subscription ready (WaitOn). It works without problems 2 years for me. From the point of view of the update, both routers have not been updated for a long time, more than a year, so it is unclear whether the revision is coming as new versions of Meteor are released.
Press F12 in browser, watch for any errors. In my case I removed a package, but did not remove the code calling that package.
It errored, and looked like Iron Router was to blame.
Removed the offending code loading some other lib I removed and hey, Iron Router works.
The problem with FlowRotuer is you have to jump through hoops to load data into a template.
It makes code complex, fragmented and hard to follow (My opinion).
Iron Router allows you to pass data in as a second argument to the render function and access it directly from the template.
With Flow Router you have to first write data to a session, then write a Template helper to pull the session data or wrap your template in a "with" element.
This is an example how FlowRouter would have you get some example into a template
Template.templateName.onCreated(function() {
Meteor.call('thirdPartyAPI', function(error, result) {
Session.set('result', result);
});
});
Then on the template side you could have:
{{#with result}}
Content that requires a context
{{/with}}
And you would have a template helper that returned the Session/ReactiveVar, e.g.
Template.templateName.helpers({
result: function() {
return Session.get('result');
}
});
A similar example with Iron Router
Router.route('/post/:_id', function () {
this.render('Post', {
data: function () {
return Posts.findOne({_id: this.params._id});
}
});
});

Angular methods (constants, config, run, factory, service), Does it matter what order you call them?

I have an application built on generator-angular-fullstack and it does a great job of allowing all my angular components to live in their own separate files.
I was just running all my code through JSLint and it asked to remove 'use strict'; from my index.module.js file as it worked out that this was the global or starting file for my entire application.
I was reviewing the JSLint warning here use-the-function-form-of-use-strict
This got me thinking, how did JSLint know that index.module.js was the starting code block.
Which then got me thinking, does it matter what order angular startup methods are called.
Can these methods be run in any order you like, or is there an expected sequential order for these calls?
angular.module('appName')
angular.module('appName').run(function() { });
angular.module('appName').config(function() { });
angular.module('appName').service(function() { });
angular.module('appName').constant('blah', 'blah');
TL;DR - no it's not.
The way angular is doing it - is when the page renders and scripts are loaded it register all the components(services\config\constants..) but do not execute them.
When the registration completes angular is starting to execute the application, providers --> config --> run and so on..
If your interested in some more detailed explanation on the way angular works under the hood you can check out this awesome article.
*forgot to mention that you must define your module first.

EmberJS Reset Warning: Library is already registered with Ember

Some background...
We have an ASP.NET app we're slowly converting over to EmberJS. We have a single Ember application we instantiate for certain portions of the site. As we migration pages they get routes in the Ember app. The goal is to have everything in Ember over time. In the interim, the user can click on links that take them back to ASP.NET portions.
Our issue is with resetting the state of the Ember app if the user either clicks back to go back into Ember or clicks on a new link that takes them back into the Ember portion.
We've tried calling .reset on the application, but doing so gives us an error saying the following. Our application is called ConsoleCli and not the standard App.
Library "ConsoleCli" is already registered with Ember
Moreover, we get the following error saying one of our modules has already been registered.
Cannot re-register: `location:history-js`, as it has already been resolved.
I tried wrapping my registration of the history module with a check, but that creates a whole other slew of errors
if(!application.__container__.lookup('location:history-js')){
application.register('location:history-js', HistoryJsLocation, { singleton: true });
}
I read https://github.com/emberjs/ember.js/issues/10310 and I think it means reset() is supposed to clear all registries once this has all been merged into the main branches.
Shouldn't called App.reset() right in the middle of using an EmberJS application just reset it with no issue?
Excuse my lack of understanding, we're just learning all of this as we go.
We're running the following versions
Ember 1.11.0-beta.2
Ember Data 1.0.0-beta.15
jQuery 2.0.3
TIA!
I think you might have run into this bug: https://github.com/emberjs/ember.js/issues/10310
Try the fix mutewinter suggests in that thread, it has worked for most people (involving myself).

Categories