Custom implementing like button in ASP .NET CORE with SignalR - asp.net-core

Hy everyone,
sorry if my question is duplicate of some, but i didn't found solution for my problem.
However, i'm trying to implement custom like button for posts in my asp.net core mvc application and everything works fine, except when i click on like button, it changes color (like on facebook, blue color etc.) not just for current logged user, but for all logged users. But when other users refresh window, everything is back to normal...
What I want is, when I click on "like" button, to update "like counter" FOR EVERYONE and to change color JUST FOR ME (when I came back some other day, that I know that I liked that post.)
Does someone know how to acomplish this?
Here's my code
Index.cshtml
#using Fitness_Centar.Data
#using Fitness_Centar.Data.Models
#using Fitness_Centar.Web.Areas.ModulClan.ViewModels
#using Fitness_Centar.Web.Helper
#model List<TimelineVM>
#{
ViewData["Title"] = "Index";
MyContext _ctx = (MyContext)ViewData["_ctx"];
User u = Context.GetLoggedUser();
int userId = -1;
if (u.Coach != null)
{
userId = u.Coach.CoachId;
}
if (u.Employee != null)
{
userId = u.Employee.EmployeeId;
}
if (u.Member != null)
{
userId = u.Member.MemberId;
}
}
<div class="row">
<div class="col-sm-12 col-md-9 col-lg-9">
<div class="box box-info custom aktivnosti">
<div class="box-header with-border padding-l-25">
<h3 class="box-title">Activities</h3>
</div>
<div class="box-body">
#foreach (var p in Model)
{
<div id="#p.Post.PostClanovaId" class="post">
<div class="user-info">
<img class="img-circle img-bordered-sm" src="~/AdminLTE/dist/img/avatar5.png" />
<div class="desc">
<span class="username">#p.Post.User.Name #p.Post.User.LastName</span>
<span class="post-description">Published: #p.Post.PostDate</span>
</div>
</div>
<div class="post-content text-justify">
<p>#p.Post.Content</p>
</div>
<div class="post-footer">
#{int n = p.Post.PostId + 1594;}
#{
var c = _ctx.Likes.Where(x => x.UserId == userId && x.PostId == p.Post.PostId).FirstOrDefault();
if (c != null && c.UserId == userId)
{
<a href="" id="post-#n" class="likeButton link-black liked" data-postid="#p.Post.PostId" data-userid="#userId">
<i class="fa fa-thumbs-o-up margin-r-5"></i>
Like
</a>
}
else
{
<a href="" id="post-#n" class="likeButton link-black" data-postid="#p.Post.PostId" data-userid="#userId">
<i class="fa fa-thumbs-o-up margin-r-5"></i>
Like
</a>
}
}
<div class="num-of-likes" id="post-#n-numOfLikes">
#p.Likes.Count()
<span class="usersThatLiked">
#{
string g = "";
foreach (var l in p.Likes)
{
g += l.User.Ime + " " + l.Clan.Prezime;
}
#g;
}
</span>
</div>
<div class="comment pull-right">
<a href="#" class="link-black">
<i class="fa fa-comments-o margin-r-5"></i>
Comments
</a>
</div>
<div class="input-group">
<input type="text" class="form-control" placeholder="Komentiraj...">
<span class="input-group-btn">
<button type="button" class="btn btn-info btn-flat"><i class="fa fa-check"></i></button>
</span>
</div>
</div>
</div>
}
</div>
</div>
</div>
javascript.js
"use strict";
var $connection = new signalR.HubConnectionBuilder().withUrl("/ModulClan/Helper/LajkHub").build();
$(".likeButton").prop("disabled", true);
$connection.on("ReceiveMessage", function (numOfLikes, postId) {
var x = postId + 1594;
var s = "#post-" + x;
if ($(s).hasClass("liked")) {
$(s).removeClass("liked");
} else {
$(s).addClass("liked");
}
$(s + "-num-of-likes").text(numOfLikes);
});
$connection.start().then(function () {
$(".likeButton").prop("disabled", false);
}).catch(function (err) {
return console.error(err.toString());
});
$(".likeButton").bind("click", function (event) {
var userId = $(this).attr("data-userid");
var postId = $(this).attr("data-postid");
$connection.invoke("SetLike", userId, postId).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
LikeHub.cs
public class LikeHub : Hub
{
private readonly MyContext _ctx;
public LikeHub (MyContext context)
{
_ctx = context;
}
public async Task SetLike(int userId, int postId)
{
Likes l = new Likes();
Likes temp = _ctx.Likes.Where(x => x.PostId == postId && x.UserId == userId).FirstOrDefault();
if(temp != null)
{
_ctx.Likes.Remove(temp);
}
else
{
_ctx.Likes.Add(l);
l.UserId = userId;
l.PostId = postId;
}
_ctx.SaveChanges();
int numOfLikes= _ctx.Likes.Where(x => x.PostId == postId).Count();
await Clients.All.SendAsync("ReceiveMessage", numOfLikes, postId);
}
}

You can identify the current user (who clicked the like button) via
var userId = $(this).attr("data-userid"); (as you did when someone clicks the like button).
But the problem is this, you are not checking for the userId when the SetLike is succeeded (inside the on ReceiveMessage javascript function).
so to solve this you need to send the userId of the user who clicked the like button from the backend to the frontend (to the on("ReceiveMessage"..) function)
e.g.: await Clients.All.SendAsync("ReceiveMessage", numOfLikes, postId, userId);
and on the ReciveMessage check if the userId you got from the backend match the current user who's browsing by var currentUserId = $(this).attr("data-userid");
if they are equal then color the like button, otherwise just update the like counter.
this way would solve your issue.
Another solution would be to send 2 requests one is specific for the user who clicked the like button and the other is to everyone to update the like counter.

Related

My web page is left without any reaction after the website is launched and the page is locked

I have web page and My web page is left without any reaction after the website is launched and the page is locked. Codes are as bellow:
#attribute [Authorize]
#inject IReciption _Reception;
<section class="p-top-10 p-bottom-10 bgcolor rtl">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="shortcode_modules">
<div class="modules__title">
<h3>Reception</h3>
#*<h3>RegReception<InfoBoxComponent StrMessage="#Message1"></InfoBoxComponent></h3>*#
</div>
<div class="text-center module--social">
<div class="social social--color--filled">
<ul>
<li>
<div>
<input type="text" #bind-value="#StrSerialNumber" placeholder="SerialNumber">
</div>
</li>
<li>
#if (!IsSaveLoading)
{
<button class="btn btn-primary" #onclick="(() => CheckTheSerial())" style="margin-top:15px;">Testing</button>
}
else
{
<button class="btn btn-primary" style="margin-top:15px;">
<i class="fa fa-spin fa-spinner"></i> Searching
</button>
}
</li>
#if (prodSrCls.Responses.Statue != LosacoWeb.Shared.Enumes.StatueResponse.NoStatus)
{
#if (prodSrCls.Responses.Statue == LosacoWeb.Shared.Enumes.StatueResponse.Success)
{
<br />
<li><h4><b class="primary">Group:</b> #prodSrCls.GoodsGroupItem_Name</h4></li>
<br />
<li><h4><b class="primary">Model:</b> #prodSrCls.Goods_GoodsName </h4></li>
}
#if (prodSrCls.Responses.Statue == LosacoWeb.Shared.Enumes.StatueResponse.Failed)
{
<br />
<li>
<h3>
<span class="danger icon-close"></span><b class="danger">
Serial Is not Correct
</b>
</h3>
</li>
}
}
</ul>
</div>
</div>
</div>
</div>
<!-- end .col-md-6 -->
</div>
<!-- end .row -->
</div>
<!-- end .container -->
</section>
And C# Programming Code Part Is As Bellow:
public bool IsSaveLoading = false;
private string serial;
public String StrSerialNumber
{
get
{
return serial;
}
set
{
serial = value;
TextChangedEvetFotCleaning();
}
}
ProdSerialClasses prodSrCls
= new ProdSerialClasses();
[Parameter]
public EventCallback<ProdSerialClasses> OnFindSerial { get; set; }
protected override async Task OnInitializedAsync()
{
IsSaveLoading = false;
}
My answer is that how I can resolve my problem. I have to use this code in a online shop project. My other pages work fine. but this page become lock after run.
Hi. Change second part to :
public bool IsSaveLoading = false;
public String StrSerialNumber = "0";
ProdSerialClasses prodSrCls = new ProdSerialClasses();
[Parameter]
public EventCallback<ProdSerialClasses> OnFindSerial { get; set; }
protected override async Task OnInitializedAsync()
{
IsSaveLoading = false;
}
you must add value to you variable StrSerialNumber = "0" because in can cause of error with null value.
I hope your code problem is solved this way.
You should also check for prolapse before using prodSrCls. If it is not null, you can use it. If you do not bet, you may still get the error.
#if(prodSrCls != null)
{
// your codes . . .
}
Please do not forget to confirm the answer.

Bootstrap Carousel change firing to late?

I have an ASP.Net Core MVC web application and in my view I have a bootstrap carousel. I am trapping for the change event so I can get additional information of the image show. My problem is the image is not changing fast enough. When the change event fires and I get the unique image name it is still on the first image not the one being shown meaning the additional information I get is wrong.
Below is my bootstrap carousel: -
<div id="divCarousel" class="carousel slide" data-interval="false" data-ride="carousel">
<ul class="carousel-indicators">
#{
int Pos = 0;
}
#foreach (var photo in Model.PhotosList)
{
if (Pos == 0)
{
<li data-target="=#divCarousel" data-slide-to=#photo.Id class="active"></li>
}
else
{
<li data-target="=#divCarousel" data-slide-to=#photo.Id></li>
}
Pos++;
}
</ul>
<!-- The slideshow -->
<div class="carousel-inner">
#{
Int16 i = 0;
}
#foreach (var photo in Model.PhotosList)
{
var photoPath = "~/Photos/" + photo.PhotoPath;
if (i == 0)
{
<div class="carousel-item active">
<img class="photoSize" src="#photoPath" alt="No Photo" asp-append-version="true">
</div>
}
else
{
<div class="carousel-item">
<img class="photoSize" src="#photoPath" alt="No Photo" asp-append-version="true">
</div>
}
i++;
}
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#divCarousel" data-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#divCarousel" data-slide="next">
<span class="carousel-control-next-icon"></span>
</a>
</div>
And here is my javascript to trap for the change event: -
#section Scripts {
<script>
function showPhotoDetails() {
var url = $('.carousel-item.active img').attr('src');
var photopath = url.split('?');
photopath[0] = photopath[0].substring(8, photopath[0].length);
$.ajax({
type: 'POST',
url: "/Photos/GetValue?path=" + photopath[0],
dataType: "json",
async: false,
success: function (data) {
$("input#txtCreatedBy").val(data.createdBy);
$("input#txtDateCreated").val(data.dateCreated);
$("textarea#txtNotes").val(data.notes);
}
});
}
$(document).ready(function () {
showPhotoDetails();
$('.custom-file-input').on("change", function () {
var fileLabel = $(this).next('.custom-file-label');
var files = $(this)[0].files;
if (files.length > 1) {
fileLabel.html(files.length + ' files selected.');
} else if (files.length == 1) {
fileLabel.html(files[0].name);
}
});
$('.carousel-control-previous').on("click", function () {
showPhotoDetails();
});
$('.carousel-control-next').on("click", function () {
showPhotoDetails();
});
});
</script>
}
I basically need to get the image name after the slide event. Any help much appreciated.
Thank you,
A managed to get this sorted. Basically rather than trapping for the click event of the previous and next I use the slid.bs.carousel class. All working fine now.

in asp.net core Component #OnClick not trigger target method

I try to use my repository data to display in card view, then press button to see more information about the item, it does not work. #OnClick is only working for JSON data
#using Microsoft.AspNetCore.Components.Web - to access #onclick and more option
repoItem - my ItemRepository for get data from database
#OnClick="(e => SelectProduct(item.Id))" - when i click item card, its shoud get item id send to SelectProduct(item.Id) method.
but it work for following link. he works with JSON data but I need to work for model data.
https://github.com/dotnet-presentations/ContosoCrafts/blob/master/src/Components/ProductList.razor
<div class="card-columns">
#foreach (var item in repoItem.GetAll())
{
<div class="card">
<div class="card-header">
<h5 class="card-title">#item.Name</h5>
</div>
<div class="card-body">
<h5 class="card-title"> Total available items : #item.Quantity</h5>
<h5 class="card-title">Price : Rs. #item.Price.00</h5>
</div>
<div class="card-footer">
<small class="text-muted">
<button #onclick="(e => SelectProduct(item.Id))"
data-toggle="modal" data-target="#productModal" class="btn btn-primary">
More Info
</button>
</small>
</div>
</div>
}
</div>
#code {
Item selectedItem;
int selectedItemId;
void SelectProduct(int productId)
{
selectedItemId = productId;
selectedItem = _context.Items.Where(x => x.Id == selectedItemId).FirstOrDefault();
ContItem();
}
int itemcnt = 0;
string cuntLable;
void ContItem()
{
if (selectedItem.Quantity != null || selectedItem.Quantity != 0)
{
itemcnt = selectedItem.Quantity;
cuntLable = itemcnt.ToString();
}
else cuntLable = "Not available ..!";
}
}
problem: #onclick=".." is not hit my selectprodect method breakpoint when clicking the button.
Solution: the mistake is Statup.cs need to add services.AddServerSideBlazor() in ConfigureServices and then add in Configure part endpoints.MapBlazorHub()
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
endpoints.MapBlazorHub();
});
after 6 hours of hard work. #onclick is worked smoothly

How to display filtered items without the submit button?

I have a filter that filters my products by manufacturer. The problem is that I want for the products to show when I click the checkbox, without having to click the Save button.
#model FilterViewModel
#{
var formController = "";
var formAction = "";
if (Model.FilterType == "name")
{
formController = "Home";
formAction = "ProductSearch";
}
if (Model.FilterType == "manufacturer")
{
formController = "Manufacturer";
formAction = "ManufacturerInfo";
}
if (Model.FilterType == "category")
{
formController = "Home";
formAction = "ProductCategory";
}
}
<h5>Filter</h5>
<br />
<form id="filterForm" asp-area="" asp-controller="#formController" asp-action="#formAction" method="get">
#if (Model.ManufacturerFilterViewModel.Count > 0)
{
<h6>Producător</h6> <!-- category filter -->
<hr />
#foreach (var manufacturer in Model.ManufacturerFilterViewModel)
{
string labelVaue = $"{manufacturer.Name} ({manufacturer.Quantity})";
<div>
<input type="checkbox" id="#manufacturer.Name" name="Manufacturer" value="#manufacturer.Name" />
<label for="#manufacturer.Name">#labelVaue</label>
</div>
}
<button type="submit" class="btn btn-sm btn-primary">Save</button>
<br /><br />
}
You can submit the form when clicking on a checkbox using JavaScript. An example for your form would be:
<script type="text/javascript">
var form = document.getElementById("filterForm"); // get the form
var inputs = document.getElementsByName("Manufacturer"); // get the checkboxes
inputs.forEach(function(input) { // iterate through the checkboxes ...
input.addEventListener("click", function () { // ... and register a listener on click ...
form.submit(); // ... that submits the form
});
});
</script>
But you might want to use jQuery. Also see this question for further information.

Use AngularJS with ASP.NET MVC 4 to detect changes

I have an existing MVC 4 application with several groups of checkboxes and I need to detect when a user has made a change, i.e. checked or unchecked a checkbox. If the user has made a change and they try to navigate away from the page I need to prompt them to save their changes. I am just learning AngularJS, but figured I could use it to detect when a checkbox state has change and also use routes in angular to detect when a user is navigating away from the page.
I have based my code on the answer here. Since the view is already being rendered by MVC I cannot use REST services and angular to populate the model and view.
HTML rendered in the view
<div id="userPermissions" class="userWrapper" ng-app="myApp.User">
<div id="actionCategories" class="section" ng-controller="UserCtrl">
<div class="actionGroupBody">
<div class="actionGroupAction">
<input type="checkbox" value="Create new users"
id="action-f9ae022b-5a53-4824-8a79-f7bbac844b11"
data-action-category="8aefed6e-b76c-453f-94eb-d81d2eb284f9"
ng-checked="isSelected('f9ae022b-5a53-4824-8a79-f7bbac844b11')"
ng-click="updateSelection($event,'f9ae022b-5a53-4824-8a79-f7bbac844b11')"/>Create new users
</div>
<div class="actionGroupAction">
<input type="checkbox" value="Edit users"
id="action-5525d5e7-e1dd-4ec3-9b1d-3be406d0338b"
data-action-category="8aefed6e-b76c-453f-94eb-d81d2eb284f9"
ng-checked="isSelected('5525d5e7-e1dd-4ec3-9b1d-3be406d0338b')"
ng-click="updateSelection($event,'5525d5e7-e1dd-4ec3-9b1d-3be406d0338b')"/>Edit users
</div>
<div class="actionGroupAction">
<input type="checkbox" value="Edit personal account"
id="action-9967c1c2-c781-432b-96df-224da760bfb6"
data-action-category="8aefed6e-b76c-453f-94eb-d81d2eb284f9"
ng-checked="isSelected('9967c1c2-c781-432b-96df-224da760bfb6')"
ng-click="updateSelection($event,'9967c1c2-c781-432b-96df-224da760bfb6')"/>Edit personal account
</div>
</div>
<div class="caption">
<label class="actionGroupCaption">Store</label> <span class="actionCategorySelectAll"><input type="checkbox" value="select all Store" id="7bace6c1-4820-46c2-b463-3dad026991f2" data-action-category="selectall"/>All</span>
</div>
<div class="actionGroupBody">
<div class="actionGroupAction">
<input type="checkbox" value="Access home page"
id="action-fba7e381-4ed8-47ce-8e85-b5133c9ba9f7"
data-action-category="7bace6c1-4820-46c2-b463-3dad026991f2"
ng-checked="isSelected('fba7e381-4ed8-47ce-8e85-b5133c9ba9f7')"
ng-click="updateSelection($event,'fba7e381-4ed8-47ce-8e85-b5133c9ba9f7')"/>Access home page
</div>
<div class="actionGroupAction">
<input type="checkbox" value="Edit settings"
id="action-2d02b77b-14a4-4136-a09f-fd51eecd2dbe"
data-action-category="7bace6c1-4820-46c2-b463-3dad026991f2"
ng-checked="isSelected('2d02b77b-14a4-4136-a09f-fd51eecd2dbe')"
ng-click="updateSelection($event,'2d02b77b-14a4-4136-a09f-fd51eecd2dbe')"/>Edit settings
</div>
<div class="actionGroupAction">
<input type="checkbox" value="Edit products"
id="action-f42f933c-a2b8-42e8-af4b-d52f90f58ddb"
data-action-category="7bace6c1-4820-46c2-b463-3dad026991f2"
ng-checked="isSelected('f42f933c-a2b8-42e8-af4b-d52f90f58ddb')"
ng-click="updateSelection($event,'f42f933c-a2b8-42e8-af4b-d52f90f58ddb')"/>Edit products
</div>
<div class="actionGroupAction">
<input type="checkbox" value="Edit orders"
id="action-92ed258b-c954-46e4-b5c9-a89fdb5c54d9"
data-action-category="7bace6c1-4820-46c2-b463-3dad026991f2"
ng-checked="isSelected('92ed258b-c954-46e4-b5c9-a89fdb5c54d9')"
ng-click="updateSelection($event,'92ed258b-c954-46e4-b5c9-a89fdb5c54d9')"/>Edit orders
</div>
</div>
</div>
</div>
here's the angular code
var app = angular.module('myApp.User', []);
app.controller('UserCtrl', function ($scope) {
$scope.entities = [{ //how to populate with checkboxes state from view? factory maybe similar to below??? // }];
$scope.selected = [];
var updateSelected = function (action, id) {
if (action == 'add' & $scope.selected.indexOf(id) == -1)
$scope.selected.push(id);
if (action == 'remove' && $scope.selected.indexOf(id) != -1)
$scope.selected.splice($scope.selected.indexOf(id), 1);
};
$scope.updateSelection = function ($event, id) {
var checkbox = $event.target;
var action = (checkbox.checked ? 'add' : 'remove');
updateSelected(action, id);
};
$scope.selectAll = function ($event) {
var checkbox = $event.target;
var action = (checkbox.checked ? 'add' : 'remove');
for (var i = 0; i < $scope.entities.length; i++) {
var entity = $scope.entities[i];
updateSelected(action, entity.id);
}
};
$scope.getSelectedClass = function (entity) {
return $scope.isSelected(entity.id) ? 'selected' : '';
};
$scope.isSelected = function (id) {
return $scope.selected.indexOf(id) >= 0;
};
$scope.isSelectedAll = function () {
return $scope.selected.length === $scope.entities.length;
};
});
app.factory('UserDataService', function () {
var service = {}
service.getData = function () {
var actions = $("input[id^=action-]");
return actions;
}
return service;
});
Whenever I click a checkbox none of the $scope functions (.updateSelection, .isSelected, etc.) fire in the controller.