Ответы пользователя по тегу Angular
  • Динамические классы в CSS и HTML используя Angular 9?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    При стандартных настройках ангуляр добавляет хтмл-элементам компонента свою метку, типа _nghost-lli-c18 или _ngcontent-rja-c18
    Всем стилям компонента автоматически добавляется эта приписка, например в браузере будет выглядеть как
    a[_ngcontent-rja-c18] {
        color: red;
    }

    В Ангуляре это зовется "инкапсуляция стилей", является дефолтным поведением и может быть выключено или изменено на использование ShadowDOM.
    Таким образом стили компонента накладываются только на тэги в компоненте. Что-то там отдельно синхронизировать не нужно.
    Ответ написан
    1 комментарий
  • Вопрос по form control в ангуляре?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер

    Мне нужно, чтобы при самом первом запросе это поле не участвовало в запросе я этого добился тем, что убрал значение по дефолту в этом поле.

    поясните более развернуто, почему такое поведение?

    Пока выглядит так, что вам нужно проверять это в запросе, форма тут роли вообще не должна играть.
    И дефолтное значение у формы всегда есть, если не указали то это undefined.
    Ответ написан
  • Почему вылетает error 'Cannot read property 'subscribe' of undefined'?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    getCerts(): Observable<any> {
      // ...
      return new Observable(observer => {
        chrome.runtime.sendMessage(editorExtensionId, message, res=> {
          // ...
           observer.next(result);
           observer.complete();
        })
    }
    })


    Домашняя работа - сократить код используя https://rxjs.dev/api/index/function/bindCallback
    Ответ написан
    Комментировать
  • Как сгенерировать разные поля input?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    вот примерно так ток добавьте материал и чтение/сохранение в ls
    Ответ написан
    Комментировать
  • Как получить доступ к chrome в Angular?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    не надо слушать вредные советы :)
    Установите типы для хрома https://www.npmjs.com/package/@types/chrome

    а потом где-нибудь создаем токен для инжектора.
    export const CHROME = new InjectionToken('CHROME');

    в провайдерах апп-модуля по этому токену провайдим значение
    providers: [
      ...
      {
        provide: CHROME,
        useValue: window.chrome,
      }
      ...
    ]

    В конструкторе вашего компонента или сервиса
    constructor(
      @Inject(CHROME) private chrome: chrome,
    )


    Это делается для того чтобы иметь возможность когда нужно эту зависимость подменить. Например подсовывать моки для тестирования.
    Но вообще можно и просто chrome или window.chrome вызвать, если вы не паритесь по поводу подмен и вообще слежением за зависимостями. Главное объяснить тайпскрипту что это валидное имя. Ну т.е. доустановить типы.

    Я могу ошибиться в мелочах, т.к. не проверял, но правильный способ в общих чертах описал.
    Ответ написан
    2 комментария
  • Как прокручивать меню?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    Определить ширину контейнера в ngAfterViewInit
    При свайпе выставлять transform: translateX(ширина * индекс) с помощью Renderer2
    Анимацию на transform в стили.
    Ответ написан
    Комментировать
  • Почему не происходит запись в базу indexedDB?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    На вид все вроде ок, надо дебажить, перерести куда-нибудь в песочницу.
    Пока могу предложить свою обертку к indexedDB, вроде работает, не тестировал толком. Может наведет на размышление.
    DbService

    export interface DbConfig {
      /** prefix for indexed db name */
      name: string;
      /** keyPath in indexed db */
      keyPath?: string;
      /** keyPath of indexed db */
      objectName: string;
    }
    
    @Injectable()
    export class DbService<T = any> {
      private version = 1;
      private db$: Observable<IDBDatabase> = this.createDb(this.config.name, this.version);
    
      constructor(
        @Inject(DB_CONFIG) private config: DbConfig,
      ) { }
    
      private createDb(name: string, version?: number): Observable<IDBDatabase> {
        const openRequest: IDBOpenDBRequest = indexedDB.open(name, version);
    
        openRequest.onupgradeneeded = (evt: IDBVersionChangeEvent) => this.onUpgradeNeeded(openRequest);
    
        return this.fromIDBRequest(openRequest).pipe(
          shareReplay(1),
        );
      }
    
      private onUpgradeNeeded(openRequest: IDBOpenDBRequest): void {
        const db = openRequest.result;
        if (db.objectStoreNames.contains(this.config.objectName)) {
          return;
        }
        db.createObjectStore(this.config.objectName, { keyPath: this.config.keyPath });
      }
    
      public save(value: T, key?: IDBValidKey): Observable<IDBValidKey> {
        return this.db$.pipe(
          mergeMap((db: IDBDatabase) => this.fromIDBRequest(
            this.createIDBObjectStore(db, 'readwrite').put(value, key)
          )),
        );
      }
    
      public saveAll(values: T[]): Observable<IDBValidKey[]> {
        return from(values).pipe(
          mergeMap((value: T, index: number) => this.save(value, index)),
          toArray(),
        );
      }
    
      public delete(key: string): Observable<undefined> {
        return this.db$.pipe(
          mergeMap(db => this.fromIDBRequest(
            this.createIDBObjectStore(db, 'readwrite').delete(key),
          ))
        );
      }
    
      public clear() {
        return this.db$.pipe(
          mergeMap(db => this.fromIDBRequest(
            this.createIDBObjectStore(db, 'readwrite').clear(),
          ))
        );
      }
    
      public retreive(key: string): Observable<T> {
        return this.db$.pipe(
          mergeMap(db => this.fromIDBRequest(
            this.createIDBObjectStore(db, 'readonly').get(key)
          )),
        );
      }
    
      public retreiveAll(): Observable<T[]> {
        return this.db$.pipe(
          mergeMap(db => this.fromIDBRequest(
            this.createIDBObjectStore(db, 'readonly').getAll()
          )),
        );
      }
    
      private createIDBObjectStore(db: IDBDatabase, mode: IDBTransactionMode): IDBObjectStore {
        const transaction: IDBTransaction = db.transaction(this.config.objectName, mode);
        return transaction.objectStore(this.config.objectName);
      }
    
      private fromIDBRequest<R>(idbRequest: IDBRequest<R>): Observable<R> {
        return new Observable<R>(observer => {
          idbRequest.onsuccess = (evt: Event) => {
            observer.next(idbRequest.result);
            observer.complete();
            evt.stopPropagation();
          };
          idbRequest.onerror = (evt: Event) => {
            observer.error(idbRequest.error);
            evt.stopPropagation();
          };
        });
      }
    
      public selectDb() {
        return this.db$;
      }
    }

    Ответ написан
  • Как с помощью RxJs показать лоадер для медленного запроса?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    https://stackblitz.com/edit/angular-ws6pee
    задержки увеличены до 1000 и 2500 для наглядности
    В случае множественных загрузок возможны коллизии, надо будет дорабатывать.
    Лоадер, дебаунсер и таймауты можно и нужно изолировать в отдельном компоненте (или директиве), который будет получать текущее значение лоадера (тут оно setLoader) как инпут параметр.
    В принципе вообще можно сделать даже пайп.


    - если запрос длится более 500 мс, то показываем лоадер
    - если лоадер уже показан, то отображать его не менее 300 мс

    Если бы эти два числа были одинаковы, можно было обойтись одним debounceTime на лоадере.
    Ответ написан
  • Что ссылкой как ее вставить что бы правильно отображалась?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    <a [routerLink]="['/dashboard/micebot/']" [queryParams]="{ a: 'serv11111121'}">/micebot</a>
    Ответ написан
    1 комментарий
  • Angular2: как при авторизации обновить header.component?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    @Injectable()
    export class UserService {
        isAuthenticated$ = new ReplaySubject(1);
      
        constructor(private http: HttpClient) { }
         
        getUser() {
            return this.http.get('/server/api/userService').pipe(
              tap(data => this.isAuthenticated$.next(!!data['login'])),
            );
        }
    }


    export class HeaderComponent implements OnInit {
          user$: Observable<User>;
          isAuthenticated$: Observable<boolean>;
    
         constructor(private userService: UserService) { }        
    
          ngOnInit() {
            this.user$ = this.userService.getUser();
            this.isAuthenticated$ = this.userService.isAuthenticated$;
         }
    }


    При использовании AsyncPipe достаточно этого, хотя даже isAuthenticated - лишний.
    Ответ написан
    9 комментариев
  • Как использовать нескольких css-фреймворков в одном проекте, не прибегая к помощи SASS/SCSS?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    Сделать как написано в статье, скомпилить стили с помощью препроцессора, получившийся CSS подключить к проекту.
    Ответ написан
    Комментировать
  • Как в angular правильно вызвать асинхронный метод с параметром из html разметки?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    <span>{{ getAddressByCode(addressCode) | async }}</span>

    AsyncPipe умеет раскрывать промисы.
    Разумеется метод будет вызываться каждый раз при проверке изменений.


    существует ли возможность в ангуляре вызывать нормальные async методы, а не только RxJs?

    Angular это все еще js и работать с асинками в нем можно. Но как правило не нужно потому, что создаются совершенно лишние обертки, rx просто удобнее.
    Для реквестов используется xhr, и его событийная природа легко конвертируется в rx поток.
    Ответ написан
  • Как работает import в angular и какая оптимизация от sharedModule?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    Импорт модуля1 в модуль2 инициализирует инжектор модуля1 и он становится доступен для инжектора модуля2.
    Создаются экземпляры провайдеров модуля1, и декларируемые сущности модуля 1 и новые экземляры провайдеров модуля1 становятся видимыми для модуля2.
    Компоненты импортировать нельзя.

    Расположение по бандлам определяет вебпак, если нет лейзи модулей то все будет в main. Если будут лейзи, то общие импорты скорее всего тоже попадут в main.
    Ваш вариант 2 ближе к реальности.
    SharedModule не нужен. Он служит типа аггрегатором для разделяемых модулей, чтобы меньше было строчек в импортах.
    Ответ написан
    1 комментарий
  • Подписаться на роут?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    Нужно либо сменить роут, например добавив хэш или query param
    Либо выключить переиспользование компонента, тогда на каждый клик компонент будет инициализироваться заново. Поместив вот это куда-нибудь выше, например в app.component
    constructor(
        private router: Router,
      ) {
        this.router.routeReuseStrategy.shouldReuseRoute = function () {
          return false;
        };
        this.router.events.subscribe((evt) => {
          if (evt instanceof NavigationEnd) {
            this.router.navigated = false;
          }
        });
      }


    Есть так же вариант ловить все клики по routerLink и вызов navigate

    upd.
    а вообще вы же должны понимать, что вам не роут надо отслеживать, а выполнить ваши действия
    1. при инициализации компонента.
    2. при нажатии на кнопку.
    Выносится в метод и вызывается в нужном месте.
    Ответ написан
  • Как реализовать правильно данный Guard?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
      return this.auth.getUser().pipe( map(user => user.err == 0));
    }
    Ответ написан
  • Что не так? В чем ошибка?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    потому что
    export class Task1Module {
      constructor(
        public distance:Observable<distance>,
        public convert_to:string
      ) {
      }
    }


    поле distance это Observable, а у него нет свойства unit
    а потом вы еще convert_out.value пытаетесь число присвоить, а оно является строкой.

    Пишите все по человечески и такое будет сразу видно.
    Ответ написан
  • Ввод только цифр?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    import { Directive } from '@angular/core';
    import { NgControl } from '@angular/forms';
    import { Subscription } from 'rxjs';
    
    @Directive({
      selector: '[numbers]',
    })
    export class NumbersDirective  {
      sub = new Subscription();
    
      constructor(
        private ngControl: NgControl
      ) { }
    
      ngOnInit() {
        this.sub = this.ngControl.valueChanges.subscribe(value => {
          this.ngControl.control.setValue(
            (value || '').replace(/[^0-9]*/g, ''),
            { emitEvent: false },
          )
        });
      }
      ngOnDestroy() {
        this.sub.unsubscribe();
      }
    }
    Ответ написан
    Комментировать
  • Перенос контента навигации из одного контейнера в другой?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    https://ng-run.com/edit/mGpNNV5K4mQirnqoMJty

    Предлагаю самостоятельно оптимизировать, перевести на потоки, сделать OnPush, разбить на компоненты и сервисы и сделать все еще более абстрактно и реюзабельно.
    Ответ написан
    2 комментария
  • Как связать front-end на Angular и back-end asp.net core?

    Xuxicheta
    @Xuxicheta Куратор тега Angular
    инженер
    МС конкретно намутила воду пытаясь в свой фреймворк адаптировать для SPA.
    Мыслите по другому.
    Если вам нужно веб-приложение, веб-приложение состоит из двух частей (как минимум) - фронт и бэк.
    Фронт это гора скриптов, которые пользователь получает от статик веб-сервера. Бэк - логика, которая умеет общаться с бд и отвечает по протоколу, доступному для фронта.
    Поскольку asp.net это такая крупная энтерпрайз штука, то и фреймворк для фронта МС выбрали крупный, энтерпрайзный - Ангуляр и попытались интегрироватся с ним как могли. (Странно что МС не нашла очередной фатальный недостаток и не взялась пилить собственный веб-фрейм)
    Спасибо им конечно, но по факту это два разных относительно незавимых приложения все равно и в доке Ангуляра вы про asp.net не найдете ничего.

    И возвращаясь к сути вопроса, да, фронт делает http запросы на бэк. Асинхронные запросы в обе стороны тоже возможны, через websocket.
    Ответ написан