Using angular2-sails module for realtime communication using sockets - sockets

I would like to use sails.io.js with angular5, so I used angular2-sails module. I managed to connect angular to sails but I didn't manage to retrieve the events from sails.js, for example when a new document is created in database. Is there something to configure sails side ? I used this.sailsService.on("user").subscribe(data => console.log("event on user")). The get and post methods are perfectly working. Sails side I put
ioclient: require('socket.io-client')('http://localhost:1337'),
io: require('sails.io.js'),
In config/http.js, instead of
var io = require('sails.io.js')( require('socket.io-client') );
because else sails cannot load
I didn't write anything in config/socket.js

angular2-sails module is deprecated so I used the io variable from sails.io.js using a service :
import {Injectable} from '#angular/core';
function _window(): any {
// return the global native browser window object
return window;
}
#Injectable()
export class SocketService {
get ioSails(): any {
return _window().io;
}
}

Related

How to provide server-side pagination with NestJS?

Given a MEVN stack using Nestjs, MongoDB(mongoose) I am working to setup server-side pagination. My approach is to use the mongoose-aggregate-paginate-v2, but I have not been able to distill what I need from my research1 to make this work within the framework of Nestjs(typescript) and mongoose. Thanks for the assist..
Following documentation on Nestjs mongoose models, and mongoose-aggregate-paginate-v2 setup, I have the following:
contact.provider.ts
import mongoose, { Connection, AggregatePaginateResult, model } from "mongoose";
import { ContactSchema } from "./contact.schema";
import aggregatePaginate from "mongoose-aggregate-paginate-v2";
import { IContact } from "./interfaces/contact.interface";
// notice plugin setup:
ContactSchema.plugin(aggregatePaginate);
// is this correct ?
interface ContactModel<T extends Document> extends AggregatePaginateResult<T> {}
// how to create model for factory use ?
export const ContactModel: ContactModel<any> = model<IContact>('Contact', ContactSchema) as ContactModel<IContact>;
export const contactProvider = [
{
provide: 'CONTACT_MODEL',
useFactory: (connection: Connection) => {
// how to instantiate model ?
let model = connection.model<ContactModel<any>>('Contact', ContactSchema);
return model;
},
inject: ['DATABASE_CONNECTION'],
},
];
I am between reading the Nestjs documentation, mongoose documentation, and typescript documentation. Somewhere along this path there is a way to provide the aggregatePaginate method on my Contact model, so that I can call like:
contact.service.ts
// Set up the aggregation
const myAggregate = this.contactModel.aggregate(aggregate_options);
const result = await this.contactModel.aggregatePaginate(myAggregate, options); // aggregatePaginate does not exist!
Review code in progress - available on this branch.
Research
Mongoose the Typescript way…?
Complete Guide for using Typescript in Mongoose with lean() function
Complete guide for Typescript with Mongoose for Node.js
MosesEsan/mesan-nodejs-crud-api-with-pagination-filtering-grouping-and-sorting-capabilities
Node.js API: Add CRUD Operations With Pagination, Filtering, Grouping, and Sorting Capabilities.
API Paging Built The Right Way
SO: Mongoose Plugins nestjs
SO: Pagination with mongoose and nestjs
There is a conflict between NestJs and mongoose-aggregate-paginate-v2 and mongoose-paginate-v2 because those plugins are using #types/mongoose, so, NestJS has conflicts if you use #types/mongoose.
I tell you this because i was trying the same thing and figure it out that is not posible to implement mongoo-aggreate-paginate-v2/mongoose-paginate-v2 till Nestjs solve the issues with #types/mongoose.
I can recommend you make a custom function by your own to do that or use https://www.npmjs.com/package/mongoose-paginate because that plugin does not require #types/mongoose.

Ionic 4 Angular 7 - passing object/data to another page [duplicate]

This question already has answers here:
Ionic 4. Alternative to NavParams
(8 answers)
Closed 4 years ago.
I would like to pass a JSON object to another page. What I've tried is to pass the JSON string using Angular router ActivatedRoute like this:
this.router.navigate(['details', details]);
and then retrieve it like this:
import { ActivatedRoute } from '#angular/router';
constructor(private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.activatedRoute.params.subscribe(extras => {
console.log(extras);
this.JSONObject = extras;
});
}
It is possible to do it this way but what happened was the nested JSON objects becomes inaccessible. It turns into this string:
"[object Object]"
The stringified JSON object is fine and accessible before I pass it. Another problem is that it appends the JSON string to the url so it doesn't look that nice. From what I read as well, it is not a good practice to pass something more than just an id this way.
I am thinking of something like passing objects as intent extras between activities in Android. I've searched the documentations, forums, and previous stackoverflow questions but I didn't found any solution that enables me to achieve this. Is there any other way of passing objects between pages using Angular router in Ionic4?
I solved it using a service with a simple setter and getter just like in this question that I later found:
Ionic 4. Alternative to NavParams
First, I create a service with setter & getter:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class NavExtrasService {
extras: any;
constructor() { }
public setExtras(data){
this.extras = data;
}
public getExtras(){
return this.extras;
}
}
Let's say I'm navigating from page A to page B, in page A:
this.navExtras.setExtras(extras)
this.router.navigateByUrl('page-b');
Then in Page B, I retrieve the extras this way:
this.location = navExtras.getExtras();
It works so far although I'm still not sure if there are better ways to do it..

Meteor: Minimongo does not synchronize with MongoDB

My Meteor application using Angular 2 and Typescript seems not to load the server data on the client side: I have followed this tutorial, both with autopublish turned on and of, but each time several tries to display data on client side with different collections failed.
Unlike in the tutorial (RC4), I am using Angular 2 RC5. My clients' main.ts looks as following:
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
Now I tried to copy the very simple sample from the tutorial using the collection "parties" (autopublish turned on).
I created the file both/collections/parties.collection.ts:
import {Mongo} from 'meteor/mongo';
import {Party} from '../interfaces/party.interface';
export const Parties = new Mongo.Collection<Party>('parties');
Instead of using the app.component.ts, I bind the collection in an another existing and functional component which looks like following:
import { Component } from '#angular/core';
import { Mongo } from 'meteor/mongo';
import template from './my-component.component.html';
import { Parties } from '../../../both/collections/parties.collection';
import { Party } from '../../../both/interfaces/party.interface';
#Component({
selector: 'my-selector',
template
})
export class MyComponent
{
parties: Mongo.Cursor<Party>;
constructor() {
this.parties = Parties.find();
alert(this.parties.count());
}
}
If I call db.parties.find({}); in the mongo console, it returns three rows, because I have set up the server side inserts from the sample.
My html template is the same as in the tutorial:
<ul>
<li *ngFor="let party of parties">
<a [routerLink]="['/party', party._id]">{{party.name}}</a>
<p>{{party.description}}</p>
<p>{{party.location}}</p>
<button (click)="removeParty(party)">X</button>
</li>
alert(this.parties.count()) returns "0" - both trying Mongo.Cursor and Mongo.Cursor. I have also tried to fetch the cursor and to alert the array. Each time I get "0" and the error message "NgFor only supports binding to Iterables such as Arrays.", but I think it fails because the client does not get the data the server has.
This is no more an issue on recent versions of angular2.0-meteor.

Angular2 multiple components using one REST call

I am part of a Angular2 application (we use beta3) and the issue is the following:
Usually we have a component that uses some service that uses some rest call and the component displays the data. Great.
However we do have a page with more then 6 components all of them using the same REST call...(the backend returns data for ALL of them) and it doesn't make sense to call 6 times the REST for each component, also it will be weird if we do some client side caching.
Is there something available out of the box ? Or a Pattern to handle such case?
Thanks.
Just do it in a shared service. If you add it only in bootstrap(..., [OtherProviders, HTTP_PROVIDERS, MyService]) each component will get injected the same instance. Store the data in the service and every component can access it
export class MyComponent {
constructor(private dataService:MyService) {
dataService.getData().subscribe(data => { this.data = data; });
}
}
export class MyService {
getData() {
if(!this.data) {
return http.get(...).map(...).subscribe(data => { this.data = data;});
}
return this.data;
}
}
The #Günter's answer really makes sense!
I don't know your code is organized but observable can also be subscribed several times. To do that you need to make them "hot" using the share operator:
export class MyService {
dataObservable:Observable;
initDataObservable() {
this.dataObservable = http.get(...).map(...).share();
}
}
Without using the share operator, corresponding request will executed several times (one per subscribe).
You can notice that the request will be executed once one subscribe method is called on the observable.

Custom Session interfering with acceptance tests

I am using ember-cli-simple-auth and ember-cli-simple-auth-devise in an ember-cli project.
I'm also customizing simple-auth's Session via an initializer:
// app/initializers/custom-session.js
import Ember from 'ember';
import Session from 'simple-auth/session';
export default {
name: 'custom-session',
before: 'simple-auth',
initialize: function(container, application) {
Session.reopen({
setCurrentUser: function() {
var id = this.get('user_id'),
self = this;
if (!Ember.isEmpty(id)) {
return container.lookup('store:main').find('user', id)
.then(function(user) {
self.set('currentUser', user);
});
}
}.observes('user_id')
});
}
};
In a simple acceptance test (one that simply calls ok(1)), I'm getting the following error
Error: Assertion Failed: calling set on destroyed object
Source:
at Adapter.extend.exception (localhost:4900/assets/vendor.js:57907:19)
at apply (http://localhost:4900/assets/vendor.js:21143:27)
at superWrapper [as exception] (localhost:4900/assets/vendor.js:20721:15)
at RSVP.onerrorDefault (localhost:4900/assets/vendor.js:59827:26)
at Object.__exports__.default.trigger (localhost:4900/assets/vendor.js:22673:13)
at Promise._onerror (localhost:4900/assets/vendor.js:23397:16)
at publishRejection (localhost:4900/assets/vendor.js:23804:17)
at http://localhost:4900/assets/vendor.js:29217:9
If I comment out the self.set('currentUser', user); line, the error goes away.
What's the appropriate way to handle this? Is there a way to ignore this initializer in tests?
I also get this log message:
No authorizer factory was configured for Ember Simple Auth - specify one if backend requests need to be authorized.
First of all you should update Ember Simple Auth to the latest version 0.6.4 that allows you to specify a custom session class without having to reopen the default Session: https://github.com/simplabs/ember-simple-auth/releases/tag/0.6.4.
Secondly, the warning about the authorizer simply means that requests going to a backend server will not be authorized (e.g. will not have an Authorization header) as no authorizer is defined. That might be ok though depending on your setup.
Regarding the destroyed object problem you could simply check whether the object is destroyed:
if (!self.isDestroyed) {
self.set('currentUser', user);
}