defining providers for an angular2 component using dart - intellij-idea

I'm writing an angular2 dart application using Intellij.
I created a provider called Auth that should be injected to the app component.
I defined the Auth service using the following code:
import 'package:angular2/core.dart';
import 'package:auth0_lock/auth0_lock.dart';
import './config.dart';
#Injectable()
class Auth {
Auth0Lock lock;
Auth() {
this.lock = new Auth0Lock(configObj.auth0.apiKey, configObj.auth0.domain);
}
updateProfileName(data) {
var profile = data['profile'] != null ? data['profile'] : data;
print(profile['name']);
}
login() {
this.lock.show(popupMode: true, options: {'authParams': {'scope': 'openid profile'}}).then(this.updateProfileName);
}
}
and the app component using the following code:
import 'package:angular2/core.dart';
import 'package:angular2/router.dart';
import 'welcome_component.dart';
import 'auth_service.dart';
#Component(
selector: 'my-app',
templateUrl: '/www/my-app.html',
providers: [Auth]
)
#RouteConfig(const [
const Route(path: '/welcome', component: WelcomeComponent, name: 'welcome')
])
class AppComponent {
Auth auth;
AppComponent(Auth auth) {
this.auth=auth;
}
}
now intellij is complaning about the providers array with the error message arguments of constant creation must be constant expressions.
I'm new to dart... but if the Component configuration needs consts, how can I provide classes to be used there ?
thanks

Just adding const should do:
providers: const [Auth]
The error you're seeing is because [Auth] creates a List that — although it contains only a const memeber — is itself not constant. (For example, it could be added to, or cleared.) Dart requires you to specify explicitly that the List is constant.

Related

Spartacus : Access Occ url on the NgModule inside Spartacus.configuration.module.ts file

I have experience on Jquery but Angular is very new to me and so is spartacus. I have been trying to configure our Spartacus to be used across multiple environments. The only solution that I could find was to use the meta tag on index.html and then grab the config based on url as mentioned by janwidmer and CarlEricLavoie. I did make a slight change from these 2 solutions though, and that was to use the environment.{env}.ts files instead of a new Backend service or keeping the config in a map in the same file.
The issue that I am facing is that the spartacus.cofniguration.module.ts file needs these values in #NgModule and I've tried everything that I could think of, but am unable to use the value of this.config.backend?.occ?.baseUrl inside the NgModule, where I need to give the value for base URL and Base site.
Below is what I am trying to do. i have written the logic that would expose the correct config object according to the OCC base url that I receive on the environment. Now over here, the console log inside the constructor prints a proper object with all the properties I need, but then the conf object right before the #NgModule, it prints undefined and the values inside the NgModule are undefined as well then.
I also tried to create a new class and import it here so I could maybe create an instance, but couldn't do that as well, as it would then need the variable/method to be static for me to be able to access it inside NgModule.
import { Injectable, NgModule } from '#angular/core';
import { FacetChangedEvent, FeaturesConfig, I18nConfig, OccConfig, provideConfig, SiteContextConfig } from "#spartacus/core";
import { environment } from '../../environments/environment';
import { defaultB2bCheckoutConfig, defaultB2bOccConfig } from "#spartacus/setup";
import { defaultCmsContentProviders, layoutConfig, mediaConfig } from "#spartacus/storefront";
import { translations } from 'src/assets/i18n-translations/translations';
import { translationChunksConfig } from 'src/assets/i18n-translations/translation-chunks-config';
import { CdcConfig, CdcRootModule, CDC_FEATURE } from '#spartacus/cdc/root';
import { EnvironmentConfigurationModule } from "../../environments/environment-configuration.module"
import { environment as envdev} from '../../environments/environment';
import { environment as envstag} from '../../environments/environment.stage';
import { environment as envprod} from '../../environments/environment.prod';
let conf : any;
console.log("before ng");
console.log(conf);
#NgModule({
declarations: [],
imports: [
],
providers: [provideConfig(layoutConfig), provideConfig(mediaConfig), ...defaultCmsContentProviders, provideConfig(<OccConfig><unknown>{
backend: {
occ: {
baseUrl: environment.baseUrl,
}
},
}), provideConfig(<SiteContextConfig>{
context: {
urlParameters: ['baseSite', 'language', 'currency'],
baseSite: [environment?.baseSite],
currency: ['USD', 'GBP',]
},
}),
provideConfig(<I18nConfig>{
i18n: {
backend:{
loadPath:'assets/i18n-translations/{{lng}}/{{ns}}.ts',
},
resources: translations,
chunks: translationChunksConfig
,fallbackLang: 'en'
},
}
), provideConfig(<FeaturesConfig>{
features: {
level: '4.2'
}
}),
provideConfig(defaultB2bOccConfig), provideConfig(defaultB2bCheckoutConfig),
]
})
export class SpartacusConfigurationModule {
urlValue : string | undefined;
env: any;
constructor(private config: OccConfig) {
this.urlValue = this.config.backend?.occ?.baseUrl;
console.log("baseurl : " + this.config.backend?.occ?.baseUrl);
if(this.urlValue?.includes('s1'))
{
this.env=envstag;
}
else if(this.urlValue?.includes('p1'))
{
this.env=envprod;
}
else{
this.env=envdev;
}
conf = this.env;
console.log("conf");
console.log(conf);
}
getConfig() {
return conf;
}
}
Apart from these solutions, we have also tried to use window.location and location.href to find the base url and work based on that. This works amazing on local, but as soon as you deploy it to the server, it says that the reference window not found/reference location not found. We tried to do this right before the NgModule, inside spartacus-configuration.module.ts
import { environment as envDev } from "../../environments/environment";
import { environment as envStage } from "../../environments/environment.stage";
import { environment as envProd } from "../../environments/environment.prod";
let loc=location.hostname;
let env;
if(loc.includes('s1'))
{
env=envStage;
}
else if(loc.includes('p1'))
{
env=envProd;
}
else{
env=envDev;
}
console.log("before ng===>>>",loc);
With environment imports, your standard build configuration will replace the environment.ts variables with the ones set by your server's environment (eg. process.env) before deployment. Therefore, you should only import from environment.ts in your code and let the server handle overriding the staging environment variables.
With location and window objects, they are not accessible on the server-side of the build because Angular Universal initially delivers a pre-rendered page readable by bots (usually html-only) for SEO purposes. The location and window objects do not exist in this instance. In Angular, window and location objects should be imported into your classes.
Use Window: https://stackoverflow.com/a/52620181/12566149
Use Location: https://stackoverflow.com/a/43093554/12566149

Nuxtjs using Vuex-module-decorator doesn't wordk

I want to use my vuex modules as classes to make my code more clean and readable. I used the section (Accessing modules with NuxtJS) at the bottom of this document: https://github.com/championswimmer/vuex-module-decorators/blob/master/README.md
I've searched for the solution for almost 3 days and tried out this link:
vuex not loading module decorated with vuex-module-decorators
but, it didn't work.
Also, I used getModule directly in the component like the solution in this issue page: https://github.com/championswimmer/vuex-module-decorators/issues/80
import CounterModule from '../store/modules/test_module';
import { getModule } from 'vuex-module-decorators';
let counterModule: CounterModule;
Then
created() {
counterModule = getModule(CounterModule, this.$store);
}
Then, accessing method elsewhere
computed: {
counter() {
return counterModule.getCount
}
}
it didn't work for me!
This is my Module in store folder in Nuxtjs project:
import { ICurrentUser } from '~/models/ICurrentUser'
import { Module, VuexModule, Mutation, MutationAction } from 'vuex-module-decorators'
#Module({ stateFactory: true, namespaced: true, name: 'CurrentUserStore' })
export default class CurrentUser extends VuexModule {
user: ICurrentUser = {
DisplayName: null,
UserId: null,
};
#Mutation
setUser(userInfo: ICurrentUser) {
this.user = userInfo;
}
get userInfo() {
return this.user;
}
}
In index.ts file in sore folder:
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import CurrentUser from './currentUser'
let currentUserStore: CurrentUser
const initializer = (store: Store<any>): void => {
debugger
currentUserStore = getModule(CurrentUser, store)
}
export const plugins = [initializer]
export {
currentUserStore,
}
I think the problem stems from this line:
currentUserStore = getModule(CurrentUser, store)
currentUserStore is created as object but properties and methods are not recognizable.
when I want to use getters or mutation I get error. For instance, "unknown mutation type" for using mutation
Probably several months late but I struggled with a similar issue, and eventually found the solution in https://github.com/championswimmer/vuex-module-decorators/issues/179
It talks about multiple requirements (which are summarised elsewhere)
The one that relates to this issue is that the file name of the module has to match the name you specify in the #Module definition.
In your case, if you rename your file from currentUser to CurrentUserStore' or change the name of the module toCurrentUser`, it should fix the issue.

How can I give an option to user to set baseurl?

I have built an app using ionic but my clients will be using different servers for accessing API. How can I give an option to set the base url by the user to call the desired server API?
There are 2 ways:
The temporary way:
This way, when the app is closed, it reset to the default api:
create a service ionic generate service
in this service, make a variable that will have the url you need
make some getter and setter
import this service where you need it (were you change your api, and in your api service)
The permanent way:
Use the file plugin to make, for example, a JSON that you will read/write with the api url in it.
set your base url in environment.ts file and use in any of service
export const environment = {
production: false,
baseUrl: 'http://localhost:3000/'
};
auth.service.ts
import { Injectable } from '#angular/core';
import { Observable} from 'rxjs';
import { HttpClient } from '#angular/common/http';
import { environment } from '../../../environments/environment';
#Injectable({
providedIn: 'root'
})
export class AuthService {
baseUrl = environment.baseUrl;
constructor(
private http: HttpClient
) { }
Userlogin(data: any): Observable<any> {
return this.http.post(this.baseUrl + 'user/login', data);
}
}

How to use Toasted inside an export default {}

I'm trying to use the package Toasted but I'm having a hard time understading how to use it.
I have a package called TreatErrors.js and I call this package to handle all errors from my application based on HTTP code returned by API a restfull API.
TreatErrors.js
import toasted from 'vue-toasted';
export default {
treatDefaultError(err){
let statusCode = err.response.status;
let data = err.response.data;
for(let field in data.errors){
if (data.errors.hasOwnProperty(field)) {
data.errors[field].forEach(message => {
toasted.show(message);
})
}
}
if(statusCode === 401){
toastr.error('Your token has expired. Please logout and login again to retrieve a new token');
}
return null;
},
}
and I'm tryin to call Toasted from within this package but I'm getting vue_toasted__WEBPACK_IMPORTED_MODULE_2___default.a.show is not a function. Any idea how I can use this Toasted inside of my own defined package?
The vue-toasted plugin must be registered with Vue first:
import Toasted from 'vue-toasted';
Vue.use(Toasted); // <-- register plugin
Then, your module could use it via Vue.toasted.show(...):
// TreatErrors.js
export default {
treatDefaultError(err) {
Vue.toasted.show(err.message);
}
}
And your Vue components could also use it via this.$toasted.show(...):
// Foo.vue
export default {
methods: {
showError(err) {
this.$toasted.show(err.message);
}
}
}

LoggedInOutlet angular2 authentication - Router v3.0.0-alpha8 - Where is ComponentInstruction?

I am using code like this to extend RouterOutlet and create app wide authentication and route protection
import {Directive, Attribute, ViewContainerRef, DynamicComponentLoader} from '#angular/core';
import {Router, ComponentInstruction} from '#angular/router';
import {Router} from '#angular/router';
import {RouterOutletMap} from '#angular/router/src/router_outlet_map';
import {RouterOutlet} from '#angular/router/src/directives/router_outlet';
import {Authentication} from '../common/authentication.service';
#Directive({
selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes:any;
isAuthenticated:boolean;
//private router: any;
constructor(public _elementRef: ElementRef, public _loader: DynamicComponentLoader,
public _parentRouter: Router, #Attribute('name') nameAttr: string, public authService:Authentication) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.isAuthenticated = authService.isLoggedIn();
//this.router = _parentRouter;
/**
* DEFINE PUBLIC ROUTES
*
* The Boolean following each route below denotes whether the route requires authentication to view.
*
* Format: key/value pair
* - key is the /route url "/login", "/signup", etc
* - value is a boolean true/false
* `true` means it's a publicly available route. No authentication required
* `false` means it's a protected route which is hidden until user is authenticated
*
*/
this.publicRoutes = {
'login': true,
'signup': true,
'404': true
};
} // end constructor
routeIsActive(routePath:string) {
return this.router.url == routePath;
}
activate(instruction: ComponentInstruction) {
// let url = instruction.urlPath;
let url = this.router.url;
// If the url doesn't match publicRoutes and they are not authenticated...
if (!this.publicRoutes[url] && !this.isAuthenticated) {
// todo: redirect to Login, may be there a better way?
this.router.navigateByUrl('/login');
}
return super.activate(instruction);
}
}
Problem is that ComponentInstruction does not exist in the new v3.0.0-alpha8 router, and the super method signature has changed. How do I update this to work in the new router? I cannot find any documentation explaining the changes.
ComponentInstruction has been deprecated. In the current RC4 version of Angular2, this class has been listed under reouter-deprecated. With RC5 coming in, this package would be dropped.
RouterOutlet has changed a lot over time and to make your class LoggedInRouterOultet work, you have to use CanActivate interface.
You can do something like this:
Have an injectable service like LoggedInActivator shown here:
import { Injectable } from '#angular/core';
import { Router, CanActivate } from '#angular/router';
import { LogInService } from './login.service';
#Injectable()
export class LoggedInActivator implements CanActivate {
constructor(private loginService: LogInService) {}
canActivate() {
return this.loginService.isLoggedIn();
}
}
Add canActivate and map it to LoggedInActivator on component while defining route:
{ path: 'home', component: HomeComponent, canActivate: [LoggedInActivator] }
I hope this helps!
because in new router, it uses CanActivate