angular2 Dynamic Services in providers - dynamic

i have a simple component like this:
import {Service1} from "serv1/sev1";
import {Service2} from "serv2/serv2";
import {Service3} from "serv3/serv3";
import {Component1} from "../........./Component"
#Component({
selector: "my-app",
directives: [Component1, CORE_DIRECTIVES],
templateUrl: "app.html",
providers: [Service1,
Service2,
Service3
]
})
export class MainComponent {
constructor(ser1: Service1, ser2: Serivce2, ser3:Service3) { }
}
bootstrap(MainComponent )
These services, via DI, will be used as Signleton in various other components of my project.
Now, i Know how to make the "Dynamic component Loader", but I m trying a way to Load, in dynamic way, these services.
So, avoid these "static" Import, read from a JSON file the services name and the services file path, maybe put them in an array, put this array inside the "providers", all of this at bootstrap time.
What do you think ?

Related

Nuxt class-based services architecture (register globally; vs manual import)

In my Nuxt app I'm registering app services in a plugin file (e.g. /plugins/services.js) like this...
import FeatureOneService from '#/services/feature-one-service.js'
import FeatureTwoService from '#/services/feature-two-service.js'
import FeatureThreeService from '#/services/feature-three-service.js'
import FeatureFourService from '#/services/feature-four-service.js'
import FeatureFiveService from '#/services/feature-five-service.js'
export default (ctx, inject) => {
inject('feature1', new FeatureOneService(ctx))
inject('feature2', new FeatureTwoService(ctx))
inject('feature3', new FeatureThreeService(ctx))
inject('feature4', new FeatureFourService(ctx))
inject('feature5', new FeatureFiveService(ctx))
}
After doing this I can access any of my service on vue instance like this.$feature1.someMethod()
It works but I've once concern, that is, this approach loads all services globally. So whatever page the user visits all these services must be loaded.
Now I've 20+ such services in my app and this does not seem optimal approach to me.
The other approach I was wondering is to export a singleton instance within each service class and import this class instance in any component which needs that service.
So basically in my service class (e.g. feature-one-service.js) I would do like to do it like this..
export default new FeatureOneService() <---- I'm not sure how to pass nuxt instance in a .js file?
and import it my component where it is required like so...
import FeatureOneService from '#/services/feature-one-service.js'
What approach do you think is most feasible? if its the second one, then how to pass nuxt instance to my singleton class?
Yep, loading everything globally is not optimal in terms of performance.
You will need to either try to use JS files and pass down the Vue instance there.
Or use mixins, this is not optimal but it is pretty much the only solution in terms of reusability with Vue2.
Vue3 (composition API) brings composables, which is a far better approach regarding reusability (thing React hooks).
I've been struggling a lot with it and the only solution is probably to inject services to the global Vue instance at the component/page level during the initialisation (in created hook), another option is to do that in the middleware (or anywhere else where you have access to the nuxt context. Otherwise you won't be able to pass nuxt context to the service.
I usually set up services as classes, call them where necessary, and pass in the properties of the context which the class depends on as constructor arguments.
So for example, a basic MeiliSearchService class might look like:
export class MeilisearchService {
#client: MeiliSearch
constructor($config: NuxtRuntimeConfig) {
super()
this.#client = new MeiliSearch({
host: $config.services.meilisearch.host,
apiKey: $config.services.meilisearch.key
})
}
...
someMethod() {
let doSomething = this.#client.method()
...
}
...
}
Then wherever you need to use the service, just new up an instance (passing in whatever it needs) and make it available to the component.
data() {
const meiliSearchService = new MeiliSearchService(this.$config)
return {
meiliSearchService,
results,
...
}
},
methods: {
search(query) {
...
this.results = this.meiliSearchService.search(query)
...
}
}
As I'm sure you know, some context properties are only available in certain Nuxt life-cycle hooks. I find most of what I need is available everywhere, including $config, store, $route, $router etc.
Don't forget about Vue's reactivity when using this approach. For example, using a getter method on your service class will return the most recent value only when explicitly called. You can't, for example, stick the getter method in a computed() property and expect reactivty.
<div v-for='result in latestSearchResults'>
...
</div>
...
computed: {
latestSearchResults() {
return this.#client.getLatestResults()
}
}
Instead, call the method like:
methods: {
getLatestResults() {
return this.#client.getLatestResults()
}
}

How to init several root provided services on app initialization in Angular 8?

I have several initializable services that implement this simple interface:
interface InitializableService {
init(): void;
}
Those services make some global subscriptions (local and external) that I need during all the live of my app. What I do now is inject those services into my app.component.ts and call them one for one. I want to automate this process.
I have found some info about ways to do this and I just found ways to do it when providing the services into an module. I provide that services in root and I do not want to change this, besides the initial arrangement take the same time to just injecting them into app.components.ts.
I tried creating a base class and extend it so each class service that implement it would become "automatic initialized" on app load but I wasn't able to get the list of services that extend that class to call init on them.
I have no idea where to start to achieve this, or if this is even possible with provideIn: 'root' services.
Have you tried to use Modules with providers ?
solution is , to create a module , something like core.module.ts
then import the module into app.module.ts.
The key is , inside of core module , using module with providers , you can initial the those useful services.
Using provide in root , I just don't like it
core.module.ts Will be something like this
import { ModuleWithProviders, NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { UsersData } from './data/users';
import { UsersService } from './mock/users.service';
const DATA_SERVICES = [
{ provide: UsersData, useClass: UsersService },
];
#NgModule({
imports: [
CommonModule,
],
providers: []
})
export class CoreModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
...DATA_SERVICES,
]
} as ModuleWithProviders;
}
}

Where to import file js in vue/nuxt

Usually I use a js code with functions to run on some events.
Now I am using nuxt.js and I wonder where to put this file or how to create a global method to use these functions in every component.
I could write the methods that I need inside every a specific component but after it wouldn't be usable outsite of it.
How to do that in vue/nuxt?
So one way to do it in vue.js is by using mixins, in nuxt you can also use mixins, then you should register them as plugins, but first:
Non global mixins
Create an extra folder for your mixins. For example in a /mixins/myMixin.js
export default {
methods: {
commonMethod() {
console.log('Hello')
}
}
}
Then import in a layout, page or component and add it via the mixins object:
<script>
import myMixin from '~/mixins/myMixin.js'
export default {
mixins: [myMixin]
}
</script>
Global mixins
For example in a new file plugins/mixinCommon.js:
import Vue from 'vue'
Vue.mixin({
methods: {
commonMethod() {}
}
})
Include the file in nuxt.config.js like that:
plugins: ['~/plugins/mixinCommon']
After that you would have the method everywhere available and call it there with this.commonMethod(). But here an advice from the vue.js docs:
Use global mixins sparsely and carefully, because it affects every
single Vue instance created, including third party components. In most
cases, you should only use it for custom option handling like
demonstrated in the example above. It’s also a good idea to ship them
as Plugins to avoid duplicate application.

vue.js 2 how use components in ES2015 webpack

I am trying to use vue-components in a webpack Typescript project but it doesn't seem to be working. I don't get any errors during the build and run, but the component HTML is never inserted into the output - I can just see the HTML source of the component instead i.e. .
My project is an ES2015 using Vue2 in VS.Net 2017. My component looks like this:
import Vue from 'vue'
import Component from 'vue-class-component'
// The #Component decorator indicates the class is a Vue component
#Component({
// All component options are allowed in here
template: '<button #click="onClick">Click!</button>'
})
export default class MyHeader extends Vue {
// Initial data can be declared as instance properties
message: string = 'Hello!'
// Component methods can be declared as instance methods
onClick(): void {
window.alert(this.message)
}
}
I have tried the official reference guide to register the component and use it. When I look at the vue-component example, it uses the same format as my project so I added the markup and properties to my Typescript class definition:
import Vue from 'vue';
import Component from 'vue-class-component';
import MyHeader from './MyHeader';
#Component({
components: {
MyHeader
}
})
export default class GetDataComponent extends Vue {
<...rest of class...>
}
but in my project the "components:" section is squiggly-underline-red with the message:
Object literal may only specify known properties, but 'components'
does not exist in type 'VueClass'. Did you mean to write
'component'?
Every example I have seen with vue-component (such as this one) uses the "components:" option in the #Component to register and use their Vue component, but in my project it doesn't seem to like it. I have also tried global registration of the component (such as this one) which includes the line:
// Register the component globally
Vue.component(my-header', MyHeader)`
but in that case I get an error like this:
Type 'typeof MyHeader' is not assignable to type 'AsyncComponent'
The Vue file works (without the Component added) and all content is rendered correctly. It's getting the Component included that doesn't work - I either get Design-time errors per above, or nothing appears in the output at all.
Is my import wrong? Or the format of the #Component? I get the feeling I am doing something that is very basic, very wrong...

Aurelia module global configuration

I have installed toastr in my Aurelia app. I am able to import and use it in different views, but I can't figure out how to set/modify its global options.
Ideas?
The most trivial place to do that is in you application constructor. You must also have your toaster script loaded at this point. Here's how your app.js could look like:
import {Router} from 'aurelia-router';
import toastr from 'toastr';
export class App {
static inject() { return [Router]; }
constructor(router) {
toastr.options.closeButton = true;
// ... setup your routing etc
}
}
I assume you already have your toaster script loaded at this point. You can also move toastr initialization to any other Aurelia constructor, or any other place, I don't see any technical restrictions.