与ModalDialogService相关的一些事情是阻止在模式中呈现的组件上的某些内容无法正常工作。
我可以将tap事件绑定到组件上,就像在示例中所做的那样,并且可以从其中的按钮关闭模态。
但是如果我将标签绑定到组件上的属性,则不显示任何内容。我的应用程序中的任何其他位置都会显示相
我怀疑必须使用entryComponents注册组件,但无法弄清楚发生了什么。
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
/* Nativescript modules */
import { NativeScriptFormsModule } from 'nativescript-angular/forms';
import { NativeScriptModule } from 'nativescript-angular/nativescript.module';
import { NativeScriptRouterModule } from 'nativescript-angular/router';
import { ModalDialogService } from 'nativescript-angular/modal-dialog';
import { registerElement } from 'nativescript-angular/element-registry';
registerElement('CardView', () => require('nativescript-cardview').CardView);
/* End nativescript modules */
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { LoginPageComponent } from './containers/login-page/login-page.component';
import { RegisterPageComponent } from './containers/register-page/register-page.component';
import { ForgotPasswordPageComponent } from './containers/forgot-password-page/forgot-password-page.component';
import { LoginFormComponent } from './components/login-form/login-form.component';
import { RegisterFormComponent } from './components/register-form/register-form.component';
import { ForgotPasswordFormComponent } from './components/forgot-password-form/forgot-password-form.component';
import { TermsComponent } from './components/terms/terms.component';
import { AuthService } from './services/auth.service';
import { AuthGuard, LazyAuthGuard } from './services/auth-guard.service';
import { AuthEffects } from './effects/auth.effects';
import { reducers } from './reducers';
import { AuthRoutingModule } from './auth-routing.module';
export const COMPONENTS = [
LoginPageComponent,
RegisterPageComponent,
ForgotPasswordPageComponent,
LoginFormComponent,
RegisterFormComponent,
ForgotPasswordFormComponent,
TermsComponent,
];
@NgModule({
imports: [
CommonModule,
NativeScriptModule,
NativeScriptRouterModule,
NativeScriptFormsModule,
],
declarations: COMPONENTS,
exports: COMPONENTS,
entryComponents: [TermsComponent],
providers: [
ModalDialogService
]
})
export class AuthModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: RootAuthModule,
providers: [AuthService, AuthGuard, LazyAuthGuard],
};
}
}
@NgModule({
imports: [
AuthModule,
AuthRoutingModule,
StoreModule.forFeature('auth', reducers),
EffectsModule.forFeature([AuthEffects]),
],
})
export class RootAuthModule {}
import { Component } from '@angular/core';
import { ModalDialogParams } from 'nativescript-angular/modal-dialog';
import { Page } from 'ui/page';
@Component({
moduleId: module.id,
selector: 'terms-dialog',
templateUrl: 'terms.component.html',
})
export class TermsComponent {
public test = 'sdfsdfsdfsd';
constructor(private params: ModalDialogParams, private page: Page) {
this.page.on('unloaded', () => {
// using the unloaded event to close the modal when there is user interaction
// e.g. user taps outside the modal page
this.params.closeCallback();
});
}
public getText(){
return 'some text';
}
public close() {
debugger;
this.params.closeCallback();
}
}
<ScrollView sdkExampleTitle sdkToggleNavButton>
<StackLayout>
<Label horizontalAlignment="left" text="test" class="m-15 h2" textWrap="true"></Label>
<Label horizontalAlignment="left" [text]="test" class="m-15 h2" textWrap="true"></Label>
<Label [text]="getText()" horizontalAlignment="left" class="m-15 h2" textWrap="true"></Label>
<Button row="0" col="1" horizontalAlignment="right" text="" class="fa" id="menu-btn" (tap)="close()"></Button>
</StackLayout>
</ScrollView>
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ViewContainerRef,
} from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { Register } from '../../models/user';
import { Config } from '../../../common/index';
import { TermsComponent } from '../terms/terms.component';
/* Mobile Specific Stuff */
import imagepicker = require('nativescript-imagepicker');
import {
ModalDialogService,
ModalDialogOptions,
} from 'nativescript-angular/modal-dialog';
@Component({
moduleId: module.id,
selector: 'bc-register-form',
templateUrl: 'register-form.component.html',
styleUrls: ['register-form.component.scss'],
})
export class RegisterFormComponent implements OnInit {
@Input()
set pending(isPending: boolean) {
if (isPending) {
this.form.disable();
} else {
this.form.enable();
}
}
@Input() errorMessage: string | null;
@Output() submitted = new EventEmitter<Register>();
form: FormGroup = new FormGroup({
username: new FormControl(''),
password: new FormControl(''),
email: new FormControl(''),
avatar: new FormControl(''),
});
avatarFilePreview: any;
constructor(
public modalService: ModalDialogService,
private viewContainer: ViewContainerRef
) {}
ngOnInit() {
this.form.get('avatar').valueChanges.subscribe(v => {
this.avatarFilePreview = v._files[0];
});
}
openDialog() {
const options: ModalDialogOptions = {
fullscreen: false,
viewContainerRef: this.viewContainer,
context: {}
};
return this.modalService.showModal(TermsComponent, options);
}
getNativescriptImagePicker() {
let context = imagepicker.create({
mode: 'single',
});
var self = this;
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
self.avatarFilePreview = selection[0];
})
.catch(function(e) {
// process error
});
}
submit() {
if (this.form.valid) {
this.submitted.emit(this.form.value);
}
}
}
{
"name": "snapnurse-apps",
"version": "0.0.0",
"repository": "<fill-your-repository-here>",
"nativescript": {
"id": "com.domain.project",
"tns-android": {
"version": "3.2.0"
},
"tns-ios": {
"version": "3.2.0"
}
},
"dependencies": {
"@angular/animations": "~4.1.0",
"@angular/common": "~4.1.0",
"@angular/compiler": "~4.1.0",
"@angular/core": "~4.1.0",
"@angular/forms": "~4.1.0",
"@angular/http": "~4.1.0",
"@angular/platform-browser": "~4.1.0",
"@angular/platform-browser-dynamic": "~4.1.0",
"@angular/router": "~4.1.0",
"@ngrx/db": "^2.0.2",
"@ngrx/effects": "^4.1.0",
"@ngrx/entity": "^4.1.0",
"@ngrx/router-store": "^4.1.0",
"@ngrx/store": "^4.1.0",
"@ngrx/store-devtools": "^4.0.0",
"@ngx-translate/core": "^6.0.1",
"@ngx-translate/http-loader": "0.0.3",
"nativescript-angular": "^3.1.0",
"nativescript-cardview": "^2.0.3",
"nativescript-imagepicker": "^4.0.1",
"nativescript-ngx-fonticon": "^3.0.0",
"nativescript-theme-core": "~1.0.2",
"ngrx-store-freeze": "^0.2.0",
"reflect-metadata": "~0.1.8",
"rxjs": "^5.4.0",
"tns-core-modules": "^3.3.0",
"zone.js": "~0.8.2"
},
"devDependencies": {
"@angular/compiler-cli": "~4.1.0",
"@ngtools/webpack": "~1.5.5",
"@types/jasmine": "^2.5.47",
"babel-traverse": "6.25.0",
"babel-types": "6.25.0",
"babylon": "6.17.4",
"copy-webpack-plugin": "~4.0.1",
"css-loader": "0.28.2",
"del": "^2.2.2",
"extract-text-webpack-plugin": "~2.1.0",
"gulp": "gulpjs/gulp#4.0",
"gulp-debug": "^3.1.0",
"gulp-rename": "^1.2.2",
"gulp-string-replace": "^0.4.0",
"lazy": "1.0.11",
"nativescript-css-loader": "~0.26.0",
"nativescript-dev-android-snapshot": "^0.*.*",
"nativescript-dev-sass": "^1.3.2",
"nativescript-dev-typescript": "~0.4.5",
"nativescript-dev-webpack": "^0.7.3",
"raw-loader": "~0.5.1",
"resolve-url-loader": "~2.0.2",
"typescript": "~2.3.4",
"webpack": "^3.7.1",
"webpack-bundle-analyzer": "^2.8.2",
"webpack-sources": "~0.2.3"
},
"scripts": {
"prepPhone": "gulp build.Phone",
"prepTablet": "gulp build.Default",
"prepCLIPhone": "gulp build.cli.Phone",
"prepCLITablet": "gulp build.cli.Default",
"ios": "npm run prepCLITablet && tns run ios",
"ios.phone": "npm run prepCLIPhone && tns run ios",
"android": "npm run prepCLITablet && tns run android",
"android.phone": "npm run prepCLIPhone && tns run android",
"phone-ios-bundle": "npm run prepPhone && tns prepare ios && npm run start-ios-bundle --uglify",
"tablet-ios-bundle": "npm run prepTablet && tns prepare ios && npm run start-ios-bundle --uglify",
"build.phone-ios-bundle": "npm run prepPhone && tns prepare ios && npm run build-ios-bundle --uglify",
"build.tablet-ios-bundle": "npm run prepTablet && tns prepare ios && npm run build-ios-bundle --uglify",
"phone-android-bundle": "npm run prepPhone && tns prepare android && npm run start-android-bundle --uglify",
"tablet-android-bundle": "npm run prepTablet && tns prepare android && npm run start-android-bundle --uglify",
"build.phone-android-bundle": "npm run prepPhone && tns prepare android && npm run build-android-bundle --uglify",
"build.tablet-android-bundle": "npm run prepTablet && tns prepare android && npm run build-android-bundle --uglify",
"ns-bundle": "ns-bundle",
"livesync": "gulp tns.Livesync",
"livesync.phone": "gulp tns.Livesync.Phone",
"publish-ios-bundle": "npm run ns-bundle --ios --publish-app",
"generate-android-snapshot": "generate-android-snapshot --targetArchs arm,arm64,ia32 --install",
"start-android-bundle": "npm run ns-bundle --android --run-app",
"start-ios-bundle": "npm run ns-bundle --ios --run-app",
"build-android-bundle": "npm run ns-bundle --android --build-app",
"build-ios-bundle": "npm run ns-bundle --ios --build-app"
}
}
答案 0 :(得分:1)
花了几个小时追踪这个问题后,我想出了一种解决方法。
创建一个名为CustomDialogService的类:
import {
DetachedLoader,
ModalDialogOptions,
ModalDialogParams,
ModalDialogService,
PAGE_FACTORY,
PageFactory
} from "nativescript-angular";
import {
ComponentFactoryResolver,
ComponentRef,
Injectable,
ReflectiveInjector,
Type,
ViewContainerRef
} from "@angular/core";
import {View} from "tns-core-modules/ui/core/view";
import {Page} from "tns-core-modules/ui/page";
interface ShowDialogOptions {
containerRef: ViewContainerRef;
context: any;
doneCallback: any;
fullscreen: boolean;
pageFactory: PageFactory;
parentPage: Page;
resolver: ComponentFactoryResolver;
type: Type<any>;
}
@Injectable()
export class CustomDialogService implements ModalDialogService {
private static showDialog({
containerRef,
context,
doneCallback,
fullscreen,
pageFactory,
parentPage,
resolver,
type,
}: ShowDialogOptions): void {
const page = pageFactory({isModal: true, componentType: type});
let detachedLoaderRef: ComponentRef<DetachedLoader>;
const closeCallback = (...args: any[]) => {
doneCallback.apply(undefined, args);
page.closeModal();
detachedLoaderRef.instance.detectChanges();
detachedLoaderRef.destroy();
};
const modalParams = new ModalDialogParams(context, closeCallback);
const providers = ReflectiveInjector.resolve([
{provide: Page, useValue: page},
{provide: ModalDialogParams, useValue: modalParams},
{provide: ViewContainerRef, useValue: containerRef}
]);
const childInjector = ReflectiveInjector.fromResolvedProviders(
providers, containerRef.parentInjector);
const detachedFactory = resolver.resolveComponentFactory(DetachedLoader);
detachedLoaderRef = containerRef.createComponent(detachedFactory, -1, childInjector);
detachedLoaderRef.instance.loadComponent(type).then((compRef) => {
compRef.changeDetectorRef.detectChanges();
const componentView = <View>compRef.location.nativeElement;
if (componentView.parent) {
(<any>componentView.parent).removeChild(componentView);
}
page.content = componentView;
parentPage.showModal(page, context, closeCallback, fullscreen);
});
}
public showModal(type: Type<any>,
{viewContainerRef, moduleRef, context, fullscreen}: ModalDialogOptions): Promise<any> {
if (!viewContainerRef) {
throw new Error(
"No viewContainerRef: " +
"Make sure you pass viewContainerRef in ModalDialogOptions."
);
}
const parentPage: Page = viewContainerRef.injector.get(Page);
const pageFactory: PageFactory = viewContainerRef.injector.get(PAGE_FACTORY);
// resolve from particular module (moduleRef)
// or from same module as parentPage (viewContainerRef)
const componentContainer = moduleRef || viewContainerRef;
const resolver = componentContainer.injector.get(ComponentFactoryResolver);
return new Promise(resolve => {
setTimeout(() => CustomDialogService.showDialog({
containerRef: viewContainerRef,
context,
doneCallback: resolve,
fullscreen: !!fullscreen,
pageFactory,
parentPage,
resolver,
type,
}), 10);
});
}
}
然后,在您的NgModule中,将此提供程序添加到您的providers数组中:
{ provide: ModalDialogService, useClass: CustomDialogService }
这会使用新的CustomDialogService覆盖默认的ModalDialogService,修复错误!