#angular #typescript #signalr #ng-class #signalr.client
Вопрос:
Я создал приложение со списком сообщений, и пользователю может понравиться/не понравиться сообщение. Для функции «Нравится» я использовал SignalR, и все работает нормально, но я хочу изменить цвет кнопки «Нравится», если зарегистрированному пользователю уже понравилось сообщение, чтобы он знал, какие сообщения ему понравились. Если пользователю не понравился пост, кнопка «Нравится» будет серой, в противном случае она будет оранжевой. Я пытался сделать это так, используя ngClass на основе логического isActive:
<button (click)="liked(post)" class="btn liked mr-5">Like <em [ngClass]="[isActive ? 'my-color' : 'active-color']" class="fa fa-thumbs-up"></em> {{post?.likes.length}}</button>
.my-color {
color: grey;
}
.active-color {
color: #e08e23;
}
export class PostCardComponent implements OnInit, OnDestroy {
@Input() post: Post;
isActive = false;
constructor(private postService: PostsService) {}
ngOnInit(): void {
this.postLiked();
this.likesSubscription = this.postService.likeMessageReceive.subscribe(result =>{
if ( result.postId === this.post.id) {
this.post = result.numOfLikes;
}
})
this.route.params.subscribe((params) => {
this.postId = params['id'];
});
}
postLiked() {
const user: User = JSON.parse(localStorage.getItem('user'));
const id = this.getDecodedToken(user.token).nameid;
var checkLike = this.post.likes.filter(like => (like.userId === parseInt(id)));
console.log(checkLike);
if(checkLike.length === 0) {
this.isActive = true;
}
return this.isActive;
}
liked(post: Post) {
const user: User = JSON.parse(localStorage.getItem('user'));
const id = this.getDecodedToken(user.token).nameid;
this.postService.setLike(parseInt(id), post.id)
.then(() => {
this.postLiked();
});
}
}
Аналогичная функциональность, созданная с помощью SignalR, выглядит следующим образом:
private hubConnection: HubConnection;
likeMessageReceive: EventEmitter<{ numOfLikes: Post, postId: number, userId: number }> = new EventEmitter<{ numOfLikes:Post, postId: number, userId: number }>();
connectHubs(user: User) {
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.hubUrl 'like', { accessTokenFactory: () => user.token,
skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets })
.build();
return this.hubConnection.start()
.then(() => {
this.hubConnection.on('ReceiveMessage', (numOfLikes, postId, userId) => {
user.id = userId;
this.likeMessageReceive.emit({ numOfLikes, postId, userId });
});
})
.catch(error => console.log(error));
}
setLike(userId: number, postId: number) {
return this.hubConnection.invoke('SetLike', userId, postId);
}
Бэкэнд:
public async Task SetLike(int userId, int postId)
{
Like l = new Like();
Like temp = _context.Likes.Where(x => x.PostId == postId amp;amp; x.UserId == userId).FirstOrDefault();
if(temp != null)
{
_context.Likes.Remove(temp);
} else
{
l.UserId = userId;
l.PostId = postId;
_context.Likes.Add(l);
}
await _context.SaveChangesAsync();
var post = await _postRepository.GetPostAsync(postId);
await Clients.All.SendAsync("ReceiveMessage", post, postId, userId);
}
Когда я не подписываюсь на сообщение, кнопка мгновенно меняется с оранжевой на серую и работает по желанию. Однако, наоборот, если мне нравится сообщение, кнопка становится серой на оранжевую только после обновления страницы, а не мгновенно. Это почему?
Комментарии:
1. Как
checkLike
isActive
выглядит / журнал? В любом случае, я предполагаю, что обертываниеthis.postLiked();
с помощью NgZone поможет, так как обратный вызов послеsetLike
того, как обещание будет выполнено, может не быть принят Angular для обнаружения изменений. ЕслиisActive
журналы is обновляются каждый раз сfalse
помощью,true
,…, но при печати пользовательского{{ isActive }}
интерфейса они не будут синхронизированы, попробуйте NgZone.2. isActive либо возвращает true/false, и checkLike выглядит так
[]
, если текущему пользователю не понравился пост, и что-то в этом роде, если ему/ей понравилось[info about user]
. Но теперь я вижу, что галочка всегда пуста, даже если пользователю понравился пост, возможно, в этом и проблема. Я до сих пор не работал с NgZone, вы имеете в виду что-то подобное?this.ngZone.run(() => { this.postLiked(() => { isActive = ... }); });
Я думаю, что называю методы неправильными, но я не вижу проблемы.3. Если это проблема с фактической установкой правильного значения
isActive
, то мы, вероятно, не сможем помочь без других подробностей. Хотя строкаthis.post.likes.length = result.numOfLikes;
также выглядит неправильно, еслиlikes
только она не является массивом иlength
не является его длиной. Что касается NgZone, у вас был пример использования в документах. Такthen(() => this.ngZone.run(() => this.postLiked()))
.4. Я понял проблему, но не знаю, почему это происходит. Когда я не люблю пост, все работает нормально, количество лайков уменьшается, а объект «Нравится» удаляется из базы данных. Однако, когда мне нравится пост, количество лайков увеличивается, но лайк не задается в базе данных, и я получаю пустой объект, подобный этому:
(2) [{…}, empty]
. Это почему? Я также опубликовал свой внутренний код.5. Что меня также беспокоит, так это то, когда и как Вы добавляете лайки, которые Вы фильтруете. Потому что , если вы делаете это на хабе
ReceiveMessage
, может быть уже слишком поздно (после настройкиisActive
). ВероятноisActive
, тогда было бы лучше рассчитатьlikesSubscription
setLike
. Или просто установитьthis.isActive = false;
, а не звонитьthis.postLiked()
. Вы знаете, что это вы, кому все равно понравился пост, так зачем утруждать себя вычислением этого.