@ionic/angular#ViewWillEnter TypeScript Examples

The following examples show how to use @ionic/angular#ViewWillEnter. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: chatroom.component.ts    From onchat-web with Apache License 2.0 6 votes vote down vote up
@Component({
  selector: 'app-chatroom',
  templateUrl: './chatroom.component.html',
  styleUrls: ['./chatroom.component.scss'],
})
export class ChatroomComponent implements ViewWillEnter {
  /** 虚拟列表项目高度 */
  itemHeight: number = CssUtils.rem2px(4.425);

  minBufferPx: number = this.window.innerHeight * 1.5;
  maxBufferPx: number = this.window.innerHeight * 2;

  constructor(
    private userService: UserService,
    public globalData: GlobalData,
    @Inject(WINDOW) private window: Window,
  ) { }

  ionViewWillEnter() {
    // 如果为空,就加载
    this.globalData.groupChatrooms || this.userService.getGroupChatrooms().subscribe(({ data }: Result<ChatSession[]>) => {
      this.globalData.groupChatrooms = data;
    });
  }

}
Example #2
Source File: friend.component.ts    From onchat-web with Apache License 2.0 6 votes vote down vote up
@Component({
  selector: 'app-friend',
  templateUrl: './friend.component.html',
  styleUrls: ['./friend.component.scss'],
})
export class FriendComponent implements ViewWillEnter {
  /** 虚拟列表项目高度 */
  itemHeight: number = CssUtils.rem2px(4.425);

  minBufferPx: number = this.window.innerHeight * 1.5;
  maxBufferPx: number = this.window.innerHeight * 2;

  constructor(
    private userService: UserService,
    public globalData: GlobalData,
    @Inject(WINDOW) private window: Window,
  ) { }

  ionViewWillEnter() {
    // 如果为空,就加载
    this.globalData.privateChatrooms || this.userService.getPrivateChatrooms().subscribe(({ data }: Result<ChatSession[]>) => {
      this.globalData.privateChatrooms = data;
    });
  }

}
Example #3
Source File: chat.page.ts    From onchat-web with Apache License 2.0 4 votes vote down vote up
@Component({
  selector: 'app-chat',
  templateUrl: './chat.page.html',
  styleUrls: ['./chat.page.scss'],
  providers: [Destroyer]
})
export class ChatPage implements OnInit, OnDestroy, AfterViewInit, ViewWillEnter {
  /** IonContent滚动元素 */
  private contentElement: HTMLElement;

  /** IonContent */
  @ViewChild(IonContent, { static: true }) ionContent: IonContent;

  /** 当前房间名字 */
  chatroomName: string = 'Loading…';
  /** 房间ID */
  chatroomId: number;
  /** 聊天室类型 */
  chatroomType: ChatroomType;
  /** 会话列表中对应的会话 */
  chatSession: ChatSession;
  /** 最先的消息,用于查询指定消息段 */
  firstMsg?: Message;
  /** 聊天记录 */
  msgList: Message[] = [];
  /** 聊天记录是否查到末尾了 */
  ended: boolean = false;
  /** 回复的消息 */
  replyMessage: Message;

  constructor(
    public globalData: GlobalData,
    private chatRecordService: ChatRecordService,
    private chatroomService: ChatroomService,
    private chatSessionService: ChatSessionService,
    private friendService: FriendService,
    private platform: Platform,
    private socket: Socket,
    private route: ActivatedRoute,
    private router: Router,
    private overlay: Overlay,
    private navCtrl: NavController,
    private destroyer: Destroyer,
    @Inject(WINDOW) private window: Window,
  ) { }

  ionViewWillEnter() {
    // 场景:从1号房间跳到2号房间,全局房间号变成2,再返回到1号房间,全局房间号变回1
    const chatroomId = +this.route.snapshot.params.id;
    if (this.globalData.chatroomId !== chatroomId) {
      this.globalData.chatroomId = chatroomId;
    }
  }

  ngOnInit() {
    this.chatroomId = +this.route.snapshot.params.id;
    this.globalData.chatroomId = this.chatroomId;

    this.loadRecords();

    // 先去聊天列表缓存里面查,看看有没有这个房间的数据
    this.chatSession = this.globalData.chatSessions.find(o => o.data.chatroomId === this.chatroomId);

    if (this.chatSession) {
      const { title, data } = this.chatSession;
      this.chatSession.unread = 0;
      this.chatroomName = title;
      this.chatroomType = data.chatroomType;
    } else {
      this.chatroomService.getChatroom(this.chatroomId).subscribe(({ data }: Result<Chatroom>) => {
        const { name, type } = data
        this.chatroomName = name;
        this.chatroomType = type;
      });
    }

    this.socket.on(SocketEvent.Message).pipe(
      takeUntil(this.destroyer),
      success(),
      filter(({ data }: Result<Message>) => data.chatroomId === this.chatroomId),
      tap(({ data }: Result<Message>) => {
        // 如果不是自己发的消息
        if (data.userId !== this.globalData.user.id) {
          this.msgList.push(data);
          return this.tryToScrollToBottom();
        }

        const has = this.msgList.some(o => (
          o.type === data.type &&
          o.tempId === data.tempId
        ));

        if (!has) {
          this.msgList.push(data);
          this.scrollToBottom();
        }
      }),
      debounceTime(3000)
    ).subscribe(() => {
      this.chatSession && this.chatSessionService.readed(this.chatSession.id).subscribe();
    });

    this.socket.on(SocketEvent.RevokeMessage).pipe(
      takeUntil(this.destroyer),
      success(),
      filter(({ data }: Result<{ chatroomId: number, msgId: number }>) => data.chatroomId === this.chatroomId)
    ).subscribe(({ data }: Result<{ chatroomId: number, msgId: number }>) => {
      const msg = this.msgList.find(o => o.id === data.msgId);
      if (msg) {
        msg.nickname = msg.userId === this.globalData.user.id ? '我' : msg.nickname;
        msg.type = MessageType.Tips;
        msg.data = new RevokeMessageTipsMessage();
      }
    });

    // 重连时,自动重发
    this.socket.on(SocketEvent.Init).pipe(
      takeUntil(this.destroyer),
      success(),
      filter(() => this.msgList.some(o => o.loading)),
    ).subscribe(() => {
      this.msgList.filter(o => o.loading).forEach(o => {
        (o as MessageEntity<AnyMessage>).send();
      });
    });
  }

  ngOnDestroy() {
    this.globalData.chatroomId = null;
  }

  ngAfterViewInit() {
    this.ionContent.getScrollElement().then((element: HTMLElement) => {
      this.contentElement = element;
    });
  }

  onMessagePush(msg: MessageEntity<AnyMessage>) {
    this.msgList.push(msg);
    msg.send();

    if (msg.data instanceof TextMessage) {
      msg.data.content = StrUtils.html(msg.data.content);
    }

    this.scrollToBottom(300);
  }

  /**
   * 加载更多消息
   * @param event
   */
  async loadMoreRecords({ target }: SafeAny) {
    if (!this.firstMsg) {
      await this.scrollToBottom();
      return target.complete();
    }

    // 暴力兼容苹果内核
    const isIos = this.platform.is('ios');
    isIos && (this.ionContent.scrollY = false);
    this.loadRecords(() => {
      isIos && (this.ionContent.scrollY = true);
      target.complete();
    });
  }

  /**
   * 加载聊天记录
   * @param complete
   */
  loadRecords(complete?: () => void) {
    if (this.ended) { return complete?.(); }

    this.chatRecordService.getChatRecords(this.firstMsg?.id || 0, this.chatroomId).pipe(
      finalize(() => complete?.())
    ).subscribe({
      next: ({ data }: Result<Message[]>) => {
        for (const msg of data) {
          this.msgList.unshift(msg);
        }

        // 如果返回的消息里少于15条,则代表这是最后一段消息了
        if (data.length < 15) {
          this.ended = true;
        }

        // 如果是第一次查记录,就执行滚动
        this.firstMsg || this.scrollToBottom(0);

        if (data.length) {
          this.firstMsg = this.msgList[0];
        }
      },
      error: ({ error }: { error: Result }) => {
        error.code === ResultCode.NoPermission && this.navCtrl.back();
      }
    });
  }

  /**
   * 滚到底部
   */
  scrollToBottom(duration: number = 500) {
    return new Promise<void>(resolve => this.window.setTimeout(async () => {
      await this.ionContent.scrollToBottom(duration);
      resolve();
    }, 30));
  }

  /**
   * 尝试滚动到底部
   */
  private tryToScrollToBottom() {
    const { scrollHeight, scrollTop, clientHeight } = this.contentElement;
    // scrollHeight - scrollTop - clientHeight 得到距离底部的高度
    const scrollBottom = scrollHeight - scrollTop - clientHeight;
    scrollBottom <= 100 && this.scrollToBottom();
  }

  more() {
    if (this.chatroomType === ChatroomType.Group) {
      this.router.navigate(['/chatroom', this.chatroomId]);
    }
  }

  /**
   * 设置好友别名
   */
  setFriendAlias() {
    // 只有私聊才可改好友别名
    if (this.chatroomType !== ChatroomType.Private) { return; }

    this.overlay.alert({
      header: '好友别名',
      confirmHandler: (data: KeyValue<string, SafeAny>) => {
        if (data['alias'] === this.chatroomName) { return; }

        this.friendService.setAlias(this.chatroomId, data['alias']).subscribe(({ code, data, msg }: Result<string>) => {
          this.chatroomName = data;
          this.overlay.toast('成功修改好友别名!', 1000);

          const chatSession = this.globalData.chatSessions.find(o => o.data.chatroomId === this.chatroomId);
          if (chatSession) {
            chatSession.title = data;
          }
        });
      },
      inputs: [{
        name: 'alias',
        type: 'text',
        value: this.chatroomName,
        placeholder: '给对方起个好听的别名吧',
        cssClass: 'ipt-primary',
        attributes: {
          maxlength: NICKNAME_MAX_LENGTH
        }
      }]
    });
  }

}
Example #4
Source File: login.page.ts    From onchat-web with Apache License 2.0 4 votes vote down vote up
@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
})
export class LoginPage implements ViewWillLeave, ViewWillEnter {
  /** 密码框类型 */
  pwdInputType: string = 'password';
  readonly usernameMaxLength: number = USERNAME_MAX_LENGTH;
  readonly passwordMaxLength: number = PASSWORD_MAX_LENGTH;

  form: FormGroup = this.formBuilder.group({
    username: [
      '', [
        Validators.required,
        Validators.pattern(USERNAME_PATTERN),
        Validators.minLength(USERNAME_MIN_LENGTH),
        Validators.maxLength(USERNAME_MAX_LENGTH)
      ]
    ],
    password: [
      '', [
        Validators.required,
        Validators.minLength(PASSWORD_MIN_LENGTH),
        Validators.maxLength(PASSWORD_MAX_LENGTH)
      ]
    ],
  });

  readonly usernameFeedback: ValidationFeedback = usernameFeedback;
  readonly passwordFeedback: ValidationFeedback = passwordFeedback;

  constructor(
    public globalData: GlobalData,
    private router: Router,
    private userService: UserService,
    private overlay: Overlay,
    private socket: Socket,
    private formBuilder: FormBuilder,
    private routerOutlet: IonRouterOutlet,
    @Inject(WINDOW) private window: Window,
  ) { }

  ionViewWillEnter() {
    this.routerOutlet.swipeGesture = false;
  }

  ionViewWillLeave() {
    this.routerOutlet.swipeGesture = true;
  }

  login() {
    if (this.form.invalid || this.globalData.navigating) { return; }

    this.globalData.navigating = true;

    const { username, password } = this.form.value;

    this.userService.login(new Login(username, password)).subscribe({
      next: ({ data }: Result<User>) => {
        this.overlay.toast('登录成功!即将跳转…', 1000);

        this.globalData.user = data;
        this.socket.connect();

        this.window.setTimeout(() => this.router.navigateByUrl('/'), 500);
      },
      error: () => {
        this.globalData.navigating = false;
      }
    });
  }

  /**
   * 切换密码输入框的TYPE值
   */
  togglePwdInputType() {
    this.pwdInputType = this.pwdInputType === 'text' ? 'password' : 'text';
  }

  /**
   * 消除表单控件的值的空格
   * @param controlName 控件名
   */
  trimAll(controlName: string) {
    const value = StrUtils.trimAll(this.form.get(controlName).value);
    this.form.controls[controlName].setValue(value);
  }

}
Example #5
Source File: reset.page.ts    From onchat-web with Apache License 2.0 4 votes vote down vote up
@Component({
  selector: 'app-reset',
  templateUrl: './reset.page.html',
  styleUrls: ['./reset.page.scss'],
})
export class ResetPage implements ViewWillLeave, ViewWillEnter {
  form: FormGroup = this.formBuilder.group({
    username: [
      '', [
        Validators.required,
        Validators.pattern(USERNAME_PATTERN),
        Validators.minLength(USERNAME_MIN_LENGTH),
        Validators.maxLength(USERNAME_MAX_LENGTH)
      ]
    ],
    password: [
      '', [
        Validators.required,
        Validators.minLength(PASSWORD_MIN_LENGTH),
        Validators.maxLength(PASSWORD_MAX_LENGTH)
      ]
    ],
    confirmPassword: [
      '', [
        Validators.required,
        Validators.minLength(PASSWORD_MIN_LENGTH),
        Validators.maxLength(PASSWORD_MAX_LENGTH)
      ]
    ],
    captcha: [
      '', [
        Validators.required,
        Validators.minLength(6),
        Validators.maxLength(6)
      ]
    ],
  }, {
    validators: SyncValidator.equal('password', 'confirmPassword')
  });

  /** 密码框类型 */
  pwdInputType: string = 'password';
  readonly usernameMaxLength: number = USERNAME_MAX_LENGTH;
  readonly passwordMaxLength: number = PASSWORD_MAX_LENGTH;
  readonly usernameFeedback: ValidationFeedback = usernameFeedback;
  readonly passwordFeedback: ValidationFeedback = passwordFeedback;
  readonly captchaFeedback: ValidationFeedback = captchaFeedback;
  /** 60秒倒计时 */
  countdown: number = 60;
  /** 倒计时计时器 */
  countdownTimer: number;

  constructor(
    public globalData: GlobalData,
    private app: Application,
    private overlay: Overlay,
    private formBuilder: FormBuilder,
    private userService: UserService,
    private routerOutlet: IonRouterOutlet,
    @Inject(WINDOW) private window: Window,
  ) { }

  ionViewWillEnter() {
    this.routerOutlet.swipeGesture = false;
  }

  ionViewWillLeave() {
    this.routerOutlet.swipeGesture = true;
  }

  sendCaptcha() {
    if (this.countdownTimer) { return; }

    this.userService.sendEmailCaptchaByUsername(this.form.value.username).subscribe(() => {
      this.overlay.toast('验证码发送至邮箱!', 1000);
    }, () => {
      this.overlay.toast('验证码发送失败!');
    });

    this.countdownTimer = this.window.setInterval(() => {
      if (--this.countdown <= 0) {
        this.window.clearInterval(this.countdownTimer);
        this.countdownTimer = null;
        this.countdown = 60;
      }
    }, 1000);
  }

  submit() {
    if (this.form.invalid || this.globalData.navigating) { return; }

    const { username, password, captcha } = this.form.value;

    this.userService.resetPassword(new ResetPassword(username, password, captcha)).subscribe(() => {
      this.overlay.toast('密码重置成功,请重新登录!', 1000);

      this.window.setTimeout(() => this.app.logout(), 500);
    });
  }

  /**
   * 消除表单控件的值的空格
   * @param controlName 控件名
   */
  trimAll(controlName: string) {
    const value = StrUtils.trimAll(this.form.get(controlName).value);
    this.form.controls[controlName].setValue(value);
  }

  /**
   * 切换密码输入框的TYPE值
   */
  togglePwdInputType() {
    this.pwdInputType = this.pwdInputType === 'text' ? 'password' : 'text';
  }

}
Example #6
Source File: register.page.ts    From onchat-web with Apache License 2.0 4 votes vote down vote up
@Component({
  selector: 'app-register',
  templateUrl: './register.page.html',
  styleUrls: ['./register.page.scss'],
})
export class RegisterPage implements ViewWillLeave, ViewWillEnter {
  /** 密码框类型 */
  pwdInputType: string = 'password';
  readonly usernameMaxLength: number = USERNAME_MAX_LENGTH;
  readonly passwordMaxLength: number = PASSWORD_MAX_LENGTH;
  readonly emailMaxLength: number = EMAIL_MAX_LENGTH;
  /** 60秒倒计时 */
  countdown: number = 60;
  /** 倒计时计时器 */
  countdownTimer: number;

  form: FormGroup = this.formBuilder.group({
    username: [
      '', [
        Validators.pattern(USERNAME_PATTERN),
        Validators.required,
        Validators.minLength(USERNAME_MIN_LENGTH),
        Validators.maxLength(USERNAME_MAX_LENGTH)
      ], [
        this.asyncValidator.legalUsername()
      ]
    ],
    email: [
      '', [
        Validators.required,
        Validators.maxLength(EMAIL_MAX_LENGTH),
        Validators.email
      ], [
        this.asyncValidator.legalEmail()
      ]
    ],
    password: [
      '', [
        Validators.required,
        Validators.minLength(PASSWORD_MIN_LENGTH),
        Validators.maxLength(PASSWORD_MAX_LENGTH)
      ]
    ],
    confirmPassword: [
      '', [
        Validators.required,
        Validators.minLength(PASSWORD_MIN_LENGTH),
        Validators.maxLength(PASSWORD_MAX_LENGTH)
      ]
    ],
    captcha: [
      '', [
        Validators.required,
        Validators.minLength(6),
        Validators.maxLength(6)
      ]
    ],
  }, {
    validators: SyncValidator.equal('password', 'confirmPassword')
  });

  readonly usernameFeedback: ValidationFeedback = usernameFeedback;
  readonly passwordFeedback: ValidationFeedback = passwordFeedback;
  readonly emailFeedback: ValidationFeedback = emailFeedback;
  readonly captchaFeedback: ValidationFeedback = captchaFeedback;

  constructor(
    public globalData: GlobalData,
    private route: ActivatedRoute,
    private router: Router,
    private formBuilder: FormBuilder,
    private asyncValidator: AsyncValidator,
    private onChatService: OnChatService,
    private systemService: IndexService,
    private userService: UserService,
    private overlay: Overlay,
    private socket: Socket,
    private routerOutlet: IonRouterOutlet,
    @Inject(WINDOW) private window: Window,
  ) { }

  ionViewWillEnter() {
    this.routerOutlet.swipeGesture = false;
  }

  ionViewWillLeave() {
    this.routerOutlet.swipeGesture = true;
  }

  register() {
    if (this.form.invalid || this.globalData.navigating) { return; }

    this.globalData.navigating = true;

    const { username, password, email, captcha } = this.form.value;
    this.userService.register(new Register(username, password, email, captcha)).subscribe({
      next: ({ data }: Result<User>) => {
        this.overlay.toast('注册成功!即将跳转…', 1000);
        this.globalData.user = data;
        this.socket.connect();

        this.window.setTimeout(() => this.router.navigateByUrl('/'), 500);
      },
      error: () => {
        this.globalData.navigating = false;
      }
    });
  }

  sendCaptcha() {
    const ctrl = this.form.get('email');
    if (ctrl.errors || this.countdownTimer) { return; }

    this.systemService.sendEmailCaptcha(ctrl.value).subscribe(({ code }: Result<boolean>) => {
      this.overlay.toast('验证码发送至邮箱!', 1000);
    }, () => {
      this.overlay.toast('验证码发送失败!');
    });

    this.countdownTimer = this.window.setInterval(() => {
      if (--this.countdown <= 0) {
        this.window.clearInterval(this.countdownTimer);
        this.countdownTimer = null;
        this.countdown = 60;
      }
    }, 1000);
  }

  /**
   * 切换密码输入框的TYPE值
   */
  togglePwdInputType() {
    this.pwdInputType = this.pwdInputType === 'text' ? 'password' : 'text';
  }

  /**
   * 消除表单控件的值的空格
   * @param controlName 控件名
   */
  trimAll(controlName: string) {
    const value = StrUtils.trimAll(this.form.get(controlName).value);
    this.form.controls[controlName].setValue(value);
  }

}