如何避免使用猫王操作员?

时间:2017-02-19 22:59:07

标签: angular typescript firebase firebase-realtime-database angularfire

我在Angular 2中使用我的网站的次数越多,Elvis Operator就越有可能成为可能的神奇力量。我所采取的每一步都涉及到如何将其正确应用于数据所做的每一件事。我觉得如果它是正常的"需要?几乎所有你在现实生活中使用的实际数据,Angular文档会提到它。

举个例子,我刚刚学会了如何为被动表单设置FormGroups。跟随Angular.io上的步骤,我的表单组看起来像这样。

createForm() {
    this.quesForm = this.fbuild.group({
        question: this.featureQuestion.question,
        id      : this.featureQuestion.id,
        name    : this.featureQuestion.name,
        answers : this.fbuild.array([])
    });
    this.setAnswers(this.featureQuestion.answers);
}

get answers(): FormArray {
    return this.quesForm.get('answers') as FormArray;
};

使用我在mock-data中创建的const,它完美无缺。然而,当真正使用"现实世界使用"它与真实数据"我不得不再花3到4天发现我需要这样做。

createForm() {
    this.quesForm = this.fbuild.group({
        question: this.featureQuestion ? this.featureQuestion.question: '',
        id      : this.featureQuestion ? this.featureQuestion.id: '',
        name    : this.featureQuestion ? this.featureQuestion.name: '',
        answers : this.fbuild.array([])
    });
    this.setAnswers(this.featureQuestion ? this.featureQuestion.answers: []);
}

我是否绑定到html,绑定到属性,通过@Input@Output,或者在函数中执行某些操作并不重要; Elvis Operator是桥上的巨魔,有一个疯狂的谜语需要一个星期的时间来弄清楚我已经想到的事情。起初我觉得这只是一个小小的怪癖他们不得不解决,但现在对我个人来说太重要了,因为它只是一个错误的结果,否则我认为会有更广泛的有关它的信息,因为这意味着NOBODY能够在现实生活中使用Angular,而无需在每一步中应用它。这意味着它必须是我正在做的事情。

以下是我目前如何从Firebase调用我的数据的示例。

服务

export class HomeService {
    BusImage : FirebaseObjectObservable<any>;

    constructor(private af: AngularFire) {}

    getBusImage() {
        this.BusImage = this.af.database.object('/page_area_business_image')
        as FirebaseObjectObservable<any>

        return this.BusImage;
    }
}

父组件

export class ExpBusinessComponent implements OnInit {

    private busImageO       : FirebaseObjectObservable<any>;
    private busImageQues01O : FirebaseObjectObservable<any>;
    private busImageQues02O : FirebaseObjectObservable<any>;

    constructor(private _homeService: HomeService) {}

    ngOnInit() {
        this._homeService.getBusImage().subscribe(BusImage => {
            this.busImageO       = BusImage.expand;
            this.busImageQues01O = BusImage.questions.question01;
            this.busImageQues02O = BusImage.questions.question02;
        });
    }
}

父模板

<h1>{{busExpInformation?.title}}</h1>
<p>{{busExpInformation?.intro}}</p>

<business-image
    [busImageI]        =  "busImageO"
    [busImageQues01I]  =  "busImageQues01O"
    [busImageQues02I]  =  "busImageQues02O">
</business-image>

子组件

export class BusinessImageComponent implements OnChanges, OnInit {
    @Input('busImageI')         busImage    : FirebaseObjectObservable<any>;
    @Input('busImageQues01I')   question01  : FirebaseObjectObservable<any>;
    @Input('busImageQues02I')   question02  : FirebaseObjectObservable<any>;

    public selectedI(selected){ this.selectedAnswer = selected };

    selectedAnswer: any;

    expbTrigger         : boolean = false;
    expb2Trigger        : boolean = false;
}

儿童模板

<multiple-choice-radio *ngIf="expbTrigger"
    [question]  = "question01"
    (selectedO) = "selectedI($event)"
></multiple-choice-radio>

GrandChild组件

export class MultipleChoiceRadioComponent implements OnInit, OnChanges {
    @Input('question') featureQuestion: QuestionModel;
    @Output() selectedO: EventEmitter<any> = new EventEmitter();

    selected = {value1: '', value2: ''};

    quesForm: FormGroup;

    public sendAnswer = (): void => {
         this.selectedO.emit(this.selected);
     }

    constructor(private fbuild : FormBuilder) {}

    ngOnChanges() {
        this.createForm();
    }

    createForm() {
        this.quesForm = this.fbuild.group({
            question: this.featureQuestion ? this.featureQuestion.question: '',
            id      : this.featureQuestion ? this.featureQuestion.id: '',
            name    : this.featureQuestion ? this.featureQuestion.name:  '',
            answers : this.fbuild.array([])
        });
        this.setAnswers(this.featureQuestion ? this.featureQuestion.answers: []);
    }

    get answers(): FormArray {
        return this.quesForm.get('answers') as FormArray;
    };

    setAnswers(answers : Answers[]){
        const answersFGs        = answers.map(answers => this.fbuild.group(answers));
        const answersFormArray  = this.fbuild.array(answersFGs);

        this.quesForm.setControl('answers', answersFormArray);
    }

    getSelected(ans) {
        this.selected = { value1: ans.id, value2: ans.answer };

    }
}

GrandChild模板

<form [formGroup]="quesForm" novalidate>
    <fieldset [attr.id]="quesForm.value.id">

        <label>
            {{quesForm.value.question}}
        </label>

        <div>

            <div *ngFor="let ans of quesForm.value.answers">
                <div>

                    <input type="radio"
                        [attr.name]  = "quesForm.value.name"
                        [attr.id]    = "ans.id"
                        [attr.value] = "ans.answer"
                        (click)      = "getSelected(ans)"
                        (click)      = "sendAnswer()"
                        hidden
                    />

                    <label [attr.for]="ans.id">
                        {{ans.answer}}
                    </label>
                </div>
            </div>

        </div>

    </fieldset>
</form>

我刚刚提供的大部分代码都被省略,以消除基本上完全相同的过程,只是将不同的数据传递到不同的地方,我也从HTML中删除了类,因为我使用的引导程序使得混乱了编码

截至目前,@Output将所选值发送到父级只会产生一些测试绑定的结果,我在整个对象上使用| json管道,但是日志是未定义的,所以如果你我觉得我这样做有什么不对,我已经意识到它无法正常工作。

我以这种方式做事的原因除了它是我可以将事情变为defined的唯一方法之外是因为GrandChild Component将在网站的其他地方用于其他的问题。有时我只是使用id来触发逻辑,有时我会将答案拉到将保存到数据库的用户数据实例中。因此,仅仅为了提取一些值而将整个模型重新发送到链上是没有意义的,而且如果值本身可以是消除针对嵌套值的头痛的数据,那么考虑我如何能够在没有Elvis Operator正确应用的情况下拉取我的数据。

我已经遇到了大量的角色技巧,我试图利用它们只是为了它们不起作用,因为它总是出现undefined当试图学习如何使它工作时是额外的很难,因为我不知道我在做错工作方面做错了什么,或者我是否在应用Elvis Operator方面做错了。我已经删除了很多关于这里的问题,原因是由于他们的支持和请求关闭它们,因为从那些与Angular一起掌握的人的角度来看,这是一个可怕的问题,或者是一种可怕的问题。所以希望有人可以帮助阐明我需要对我的数据做些什么,以便能够像Angular.io建议的那样做事,而不需要所有额外的意外修复和解决方法只是因为我调用了一个真正的数据库和不是本地定义的模拟数据。

2 个答案:

答案 0 :(得分:1)

您正在使用被动表单,这意味着您最终将拥有大量[无用的]代码。

除非您特别需要反应形式,否则只需使用模板驱动的表单。

答案 1 :(得分:0)

您可以使用*ngIf打包更大的区域,甚至无法到达需要?.的位置。

<h1>{{busExpInformation?.title}}</h1>
<p>{{busExpInformation?.intro}}</p>

可能是

<ng-container *ngIf="busExpInformation">
  <h1>{{busExpInformation.title}}</h1>
  <p>{{busExpInformation.intro}}</p>
</ng-container>

如果您使用ng-container包装整个组件模板并列出所有带有busExpInformation && a && b && c的异步加载字段,则可能永远不需要?.

您还可以使用解析程序来阻止在数据可用之前添加组件(https://angular.io/docs/ts/latest/guide/router.html#!#resolve-guard