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.
Related
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
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.
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.
I was trying to add additional custom field in the checkout screen and here is my code:
<div class="additional-checkout-fields" style="display:none">
<div class="fieldset fieldset--address-type" data-additional-fields>
<div class="field field--optional field--address-type">
<h2 class="additional-field-title">ADDRESS TYPE</h2>
<div class="field__input-wrapper">
<label>
<input data-backup="Residential" class="input-checkbox" aria-labelledby="error-for-address_type" type="checkbox" name="checkout[Residential]" id="checkout_attributes_Residential" value="Residential" />
<span>Residential</span>
</label>
<label>
<input data-backup="Commercial" class="input-checkbox" aria-labelledby="error-for-address_type" type="checkbox" name="checkout[Commercial]" id="checkout_attributes_Commercial" value="Commercial" />
<span>Commercial</span>
</label>
</div>
</div>
</div>
</div>
<script type="text/javascript">
if (window.jQuery) {
jquery = window.jQuery;
} else if (window.Checkout && window.Checkout.$) {
jquery = window.Checkout.$;
}
jquery(function() {
if (jquery('.section--shipping-address .section__content').length) {
var addType = jquery('.additional-checkout-fields').html();
jquery('.section--shipping-address .section__content').append(addType);
}
});
</script>
It returns the checkout page like this -
The problem is - once I click continue button and comes back to this page again, I don't see the checkbox checked. I feel the values are not being passed or may be something else.
What am I missing?
From the usecase, it looks like you want the user to select the Address Type either Residential or Commercial so a raido button group seems more suitable. I have edited the HTML to create the Radio Button instead of Checkbox. To maintain the state, I have used Session Storage. You may also replace Session Storage with Local Storage if you want to do so. For explanation check code comments.
<div class="additional-checkout-fields" style="display:none">
<div class="fieldset fieldset--address-type" data-additional-fields>
<div class="field field--optional field--address-type">
<h2 class="additional-field-title">ADDRESS TYPE</h2>
<div class="field__input-wrapper">
<label>
<input class="input-radio" aria-label="" type="radio" name="checkout[address_type]" id="checkout_attributes_Residential" value="residential" checked>
<span>Residential</span>
</label>
<label>
<input class="input-radio" aria-label="" type="radio"name="checkout[address_type]" id="checkout_attributes_Commercial" value="commercial">
<span>Commercial</span>
</label>
</div>
</div>
</div>
</div>
JavaScript part
<script type = "text/javascript" >
if (window.jQuery) {
jquery = window.jQuery;
} else if (window.Checkout && window.Checkout.$) {
jquery = window.Checkout.$;
}
jquery(function() {
if (jquery('.section--shipping-address .section__content').length) {
var addType = jquery('.additional-checkout-fields').html();
jquery('.section--shipping-address .section__content').append(addType);
// Get saved data from sessionStorage
let savedAddressType = sessionStorage.getItem('address_type');
// if some value exist in sessionStorage
if (savedAddressType !== null) {
jquery('input[name="checkout[address_type]"][value=' + savedAddressType + ']').prop("checked", true);
}
// Listen to change event on radio button
jquery('input[name="checkout[address_type]"]').change(function() {
if (this.value !== savedAddressType) {
savedAddressType = this.value;
sessionStorage.setItem('address_type', savedAddressType);
}
});
}
});
</script>
You are responsible for managing the state of your added elements. Shopify could care a less about stuff you add, so of course when you flip around between screens, it will be up to you to manage the contents. Use localStorage or a cookie. Works wonders. As a bonus exercise, ensure that your custom field values are assigned to the order when you finish a checkout. You might find all your hard work is for nothing as those value languish in la-la land unless you explicitly add them as order notes or attributes.
I am new to backbone and Marionette.
My requirement is,
I have a main grid having few rows. If i select a row from grid i need to fetch the details and display on the same page.
Binding the grid is working fine. But when i click on the row data is not binding to html template. I am unable to find out the issue.
Below is my html template for row details
<script id="selected-broker-details-tmpl" type="text/x-handlebars-template">
<div id="pnl-broker-details" class="panel panel-default">
<div class="panel-heading">
Broker Details
</div>
<div id="broker-details-container" class="panel-body">
<div class="col-md-6">
<div class="form-group">
<label for="inputbrokerName" class="col-sm-3 control-label">BrokerName</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="inputbrokerName" placeholder="Broker Name" value="{{BrokerName}}">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="inputMnemonic" class="col-sm-3 control-label">Mnemonic</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="inputMnemonic" placeholder="Mnemonic" value="{{Mnemonic}}">
</div>
</div>
</div>
</div>
</div>
</script>
Backbone view declaration
App.Views.BrokerDetails = Backbone.View.extend({
initialize: function () {
this.listenTo(this.model, 'change', this.render);
},
el: '#details',
template: brokerTemplates.BrokerDetailsTempalte,
render: function () {
this.$el.html(this.template({}));
}
});
Model and collection declaration
var BrokderDetails = Backbone.Model.extend({
BrokerId: null,
BrokerName: null,
Mnemonic: null,
OASYSMnemonic: null
});
var BrokerDetailsCollection = Backbone.Collection.extend({
initialize: function (options) {
this.model = BrokderDetails;
this.url = '/api/BrokerSelections/SelectedBroker/';
}
,
setParam: function (str) {
this.url = '/api/BrokerSelections/SelectedBroker/' + str;
this.fetch();
},
parse: function (data) {
return data;
}
});
click event in main grid
events: {
"click .selection": "selectedBroker",
},
selectedBroker: function (e) {
var details = new BrokerDetailsCollection();
var brokerdetails = new App.Views.BrokerDetails({ model: null, collection: details });
details.setParam($(e.currentTarget).data("id"));
details.fetch();
brokerdetails.render();
},
Now there are 2 issues,
1. Click event is firing 2 times, if i select a row i main grid
2. Model data is not binding to html template. I mean html template is displayed, but with empty values in textboxes