Ng-Class doesn't detect changes - javascript

On page I have ng-repeat which iterates through items in collection. Every item has property status according to which I add some class or don't. And every item has button, onclick it change item status and make PUT request to API.
As my collection on page is updated every 2 minutes, I have problem after few updates. After 5-6 minutes I make click on button, which make PUT request (successful), but my ng-class function doens't detect that status of item is changed.
<div class="one-third" ng-repeat="request in requests track by request.id">
<div class="incoming_request" ng-class="actionClass(request)">
<h2 ng-class="DayTypesClasses[request.typeId]" ng-bind="request.type"></h2>
<hr>
<div class="request_description">
<p><span>Description:</span></p>
<p ng-bind="request.baseComment"></p>
</div>
<div class="request_resolve">
<hr>
<div class="textarea-holder">
<textarea placeholder="Your comment..." ng-model="request.newComment" ng-model-options="{ updateOn: 'default blur'}"></textarea>
</div>
<div class="button-container">
<button ng-click="approve(request);" class="btn btn-primary">Confirm</button>
<button ng-click="reject(request);" class="btn btn-default pull-right" am-hide-request-resolve-div>Reject</button>
</div>
</div>
</div>
</div>
and JS-code
$scope.approve = function (request) {
var status = State.APPROVED;
var currentUserComment = request.comments.filter(function(comm) {
return comm.userId == user.id && comm.status == "Pending";
})[0];
currentUserComment.status = status; //change status
currentUserComment.text = request.newComment;
delete request.newComment;
if (!currentUserComment) {
request.isProcessing = false;
return;
}
Comments.update(currentUserComment, function() {
// $rootScope.$broadcast('daysUpdated');
});
request.isProcessing = false;
};
Ng-class function :
$scope.actionClass = function(request) {
var currentUserComment = request.comments.filter(function(comment) {
return comment.userId == user.id;
})[0];
//after click here status for every item isn't changed. Tested in debug mode
if (!currentUserComment || currentUserComment.status == State.APPROVED || currentUserComment.status == State.REJECTED) {
return 'you-approved';
}
}
So as result after few updates of my collection (requests collection I mean) onclick js isn't able to add class you-approved.
I've missed one imporatnt detail - I change status not to item request but for item, that exists in request.comments. So I can't just write ng-class="{'you-approved': request.approved}"
As #Cyril suggested I've tried to use this peace of code in my controller
$scope.$apply(function(){$scope.requests = CurrentUserData.getRequests();}) but receive error $digest already in progress.
Also I've tried to use angualr service $interval instead of window.setInterval function that updates collection requests every 2 minutes, but it doesn't seem to help.

have a look at:
https://docs.angularjs.org/api/ng/directive/ngClass
your ng-class expression doesnt need to return the class property but a json that holds the class name with a condition
so change
<h2 ng-class="DayTypesClasses[request.typeId]" ng-bind="request.type"></h2>
to:
<h2 ng-class="{'you-approved': request.approved}" ng-bind="request.type"></h2>
and JS-code update the approved parameter

How about:
ng-class="{'you-approved': !currentUserComment || currentUserComment.status == State.APPROVED || currentUserComment.status == State.REJECTED}"
Here is an example of that logic using a plunker:
https://plnkr.co/edit/hoTnrLBAibMJ0wd2WMzm?p=info
HTML:
<button ng-click="setApproved()">Set Approved</button>
<button ng-click="setRejected()">Set Rejected</button>
<button ng-click="setSomethingElse()">Set Something Else</button>
<hr />
<span ng-class="{'you-approved': !currentUserComment || currentUserComment.status == 'approved' || currentUserComment.status == 'rejected'}">Test</span>
Controller JS:
$scope.setApproved = function(){
$scope.currentUserComment = {
status: 'approved'
}
}
$scope.setRejected = function(){
$scope.currentUserComment = {
status: 'rejected'
}
}
$scope.setSomethingElse = function(){
$scope.currentUserComment = {
status: 'somethingElse'
}
}
https://docs.angularjs.org/api/ng/directive/ngClass

Related

I can not check true or false on window.onload in localStorage

I am have 3 li blocks:
HTML:
<li class="contact">
<p class="circle-name"></p><p class="person">Brad Morison</p>
<section class="sub-drop">
<span class="number">
+123-45-67
</span>
<span class="time-work">
<input type="text" placeholder="Time work guides">
</span>
</section>
</li>
and plus yet 2 some blocks with another name in class="person".
If i am click on name (class="person"), that class get new class and new styles. If i am again click, then remove class(i use classList.toggle).
When i am click on any name in class="person", that name write in localStorage (example: if i click <p class="person">Brad Picture</p>, then in localStoge write key 'Brad Picture' with value true). Value in localStorage = true or false. True if new class was add, false if again click(delete new class).
My problem:
If key in localStorage = true
window.onload i am try check:
if(name in localStorage == true){ //and === true
//Add class
}
or
if((localStorage.getItem(name)) == true){ //and === true
//Add class
}
that no work
full JS code:
if on load page name = true add new class
guide = document.querySelectorAll('.person');
index = 0;
[].slice.call(guide).forEach(names);
function names(n,i){
let name = n.innerHTML;
n.addEventListener('click', function(){
index = i;
check = n.classList.toggle('day-off');
localStorage.setItem(name, check);
});
if(localStorage.getItem(name) === true){
n.classList.add('day-off');
}
};
What's my wrong. What should I do?

how i can keep modal open after click?

My question is different and didn't get any solution.Question is when i click on active modal opens for 1 sec and then page refresh and change status active to inactive.
I want to keep modal open when i click on active then after hitting send from modal page reloads and change status to inactive.
My Modal:
<div class="modal fade text-left" id="small" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel19"
aria-hidden="true">
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
<form method="post">
<input type="hidden" name="_token" value="{{csrf_token()}}">
<div class="modal-header">
<h4 class="modal-title" id="heading-name">Reason</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label class="receiver" for="to">To: </label>
</div>
<div class="form-group">
<textarea type="text" class="form-control" name="message" id="message"></textarea>
</div>
</div>
<input type="hidden" name="message_value" id="message_value">
<div class="modal-footer">
<button type="button" class="btn grey btn-outline-secondary" data-dismiss="modal">
Close
</button>
<button type="submit" class="btn btn-outline-primary" data-target="myModalLabel19"
data-toggle="modal">Send
</button>
</div>
</form>
</div>
</div>
</div>
For Loop:
for (var i = 0; i < response.data.length; i++) {
if (response.data[i]['status'] == 1) {
operatorStatus = "Active";
statusColor = "<button class='btn btn-primary' onclick='fn_statusUpdate("+response.data[i]['id']+",0);reason("+response.data[i]['id']+")'>Active</button>";
} else {
operatorStatus = "Active";
statusColor = "<button class='btn btn-danger' onclick='fn_statusUpdate("+response.data[i]['id']+",1)'>Inactive</button>";
}
}
Function:
function reason(id) {
$('.receiver').text('To: ' + id);
$('#message_value').val(id);
console.log((JSON.stringify(id)));
$('#small').modal('show');
}
Pseudo Code
Okay, rather than re-writing the code for you, I'm just gonna write some pseudo code for you, simply because I'm not sure about how it all works or how it all ties together, etc...
So, you want to be able to do some stuff and remember the values prior to the page being refreshed, as far as I'm aware. So, I'd do something like this...
On load
...
if (sessionStorage.getItem('key') != null) {
// Show modal or set state to active or whatever...
} else {
// Hide modal and set state to inactive or whatever...
}
On State Change
....
if (state.active) {
// Do something...
} else {
// Do something else...
}
Explanation
I think you get where I'm going with this? If not it's really quite simple, if you have some value stored in session storage, then you can set the state to active and show the modal. I mean I think that's what you're trying to achieve?
Otherwise, just hide it all and set the state to inactive. I mean if you have many modals, then you could store an object into session storage using something like the code I've written below(keep in mind I've not tested this code):
const Session = {
get: key => {
try {
JSON.parse(sessionStorage.getItem(key));
} catch (e) {
return sessionStorage.getItem(key);
}
},
set: (key, data) => {
try {
sessionStorage.setItem(key, JSON.stringify(data));
} catch (e) {
sessionStorage.setItem(key, data);
}
}
};
So with this, you could just set some object, i.e. modalStates in you JavaScript, and then execute some check on load to check the state of each modal? I mean I'm not sure if you'd want to only allow only one modal to be active at any given time or if you'd want multiple to be active and open, etc...
Edit
Here's a simple demo, it won't work on here if I'm not mistaken, but if you try it on JSFiddle, I believe it should work without a problem. Again, this is just an example, it's merely here to give you an idea of how to solve your problem.
const dhtml = document.getElementById("demo");
const modal = document.getElementById("mdoal");
const btn = document.getElementById("change");
let state = {};
// Simple on error function.
const log = arg => {
console.clear();
console.log(arg);
};
// Simple get state function.
const getState = () => {
try {
if (JSON.parse(sessionStorage.getItem("demo")) != null) {
state = JSON.parse(sessionStorage.getItem("demo"));
} else {
state = {};
}
} catch (e) {
//log(e);
}
return state;
};
// Simple set state function.
const setState = () => {
try {
state = sessionStorage.setItem("demo", JSON.stringify(state));
} catch (e) {
//log(e);
}
};
// A simple on state change function.
const updateState = () => {
if (state.active == null) {
state.active = true;
} else {
state.active = !state.active;
}
setState();
log('State changed.');
};
// A simple render function.
const render = () => {
if (state.active == null || state.active == false) {
dhtml.textContent = 'Inactive';
modal.style.display = 'none';
} else {
dhtml.textContent = 'Active';
modal.style.display = 'block';
}
};
// A simple click handler for the change button.
const clickHandler = () => {
updateState();
getState();
render();
// window.location.reload(); // Simulate a http refresh/redirect.
};
// A simple on load function.
const onLoad = () => {
getState(); // Update the state object.
render(); // Initial render;
btn.onclick = clickHandler;
};
onLoad();
<div id="demo">
<p>Inactive</p>
</div>
<div id="mdoal" style="display: none">
<p>Hello World!</p>
</div>
<button id="change">state change</button>
You can use localStorage to achieve this basically, you don't have full code so I m assuming and and giving you an example:
function reason(id) {
$('.receiver').text('To: ' + id);
$('#message_value').val(id);
console.log((JSON.stringify(id)));
localStorage.setItem('isModalActive', '1'); // Add is modal active
$('#small').modal('show');
}
So now you set isModalActive 1 to users localStorage than you can check onload
$( document ).ready(function() {
if(localStorage.getItem('isModalActive') == '1'){
$('#small').modal('show');
}
});
Than when you closing to modal dont forget to change the value to 0
localStorage.setItem('isModalActive', '0'); // Add is modal not Active
Hope it helps.

Show button after function

I have a search function and a button. I only want the button to appear after the search successfully returns a result, how can I do so?
HTML:
<input type="text" class="searchFeature" ng-model="selected" ng-keyup="$event.keyCode == 13 && searchFunction()" uib-typeahead="value for value in themename | filter:$viewValue | limitTo:7" placeholder="Start your search here.">
<button>DL</button>
JavaScript:
$scope.searchFunction = function() {
// searchLayer.clearLayers();
for ( var i = 0; i < $scope.allTheme.length; i++) {
if ($scope.selected == $scope.allTheme[i].THEMENAME)
{
$scope.selectedTheme = $scope.allTheme[i].QUERYNAME;
apiURL = 'url';
$http.get(apiURL).then(function(response) {
$scope.apiResult = response.data.SrchResults;
$scope.apiResult.splice(0,1);
for (var i= 0; i < $scope.apiResult.length; i++) {
if ($scope.apiResult[i].Type == "Point"){
$scope.dataLatLng.push($scope.apiResult[i].LatLng)
$scope.Lat.push($scope.dataLatLng[i].split(',')[0]);
$scope.Lng.push($scope.dataLatLng[i].split(',')[1]);
L.marker([$scope.Lat[i], $scope.Lng[i]], {icon: greenIcon}).bindPopup($scope.apiResult[i].NAME).addTo(searchLayer);
}
}
})
}
}
}
What I tried doing:
<a ng-href="" ng-click="" ng-if="selectedTheme ==''" download>SHP</a>
you can add some flag in your angular controller and set this flag into your search function if successful and then you can use
<button ng-if="flagOn">DL</button>
This can be done by using ng-show directive
<button ng-show="showButton">DL</button>
In the search fuction after getting executed set $scope.showButton variable to true.
<button ng-if="trunOn">Search</button>
Or
<button ng-show="trunOn">Search</button>
Add ng-if in html button element and
Add condition in that function after the search successfully returns a result.
Example: $scope.trunOn = true;

Validate checkbox with AngularJs

Again i'm having trouble with checkboxes. I'm getting info from an API and showing like checkbox. The problem comes when i'm triying to add a validation. This is a part of my code:
(function() {
'use strict';
var fact = {
templateUrl: './app/components/fact.components.html',
controller: factCtrl
};
angular.module('fApp').component('odcFacturas', fact);
factCtrl.$inject = ["$scope", "couponApi"];
function factCtrl($scope, couponApi) {
var vm = this;
vm.clientOrder = null;
vm.all = false;
vm.sendData = function() {
vm.apiData = couponApi.get({
idOrder: vm.idOrder
}).$promise.then(function(data) {
for (var i = 0; i < data.Response.length; i++) {
data.Response[i].Select = vm.all;
}
vm.coupons = data.Response;
vm.combo = data.Response.length > 0;
});
}
Here i call the info, and the next part of my code check all the checkboxes:
vm.selectAll = function() {
for (var i = 0; i < vm.coupons.length; i++) {
vm.coupons[i].Select = vm.all;
}
if (vm.all == 0) {
alert("Select at least one coupon");
}
}
How can I trigger three validations with a submit button? I mean: what I want to do is validate three cases:
if the checkbox "select all checkboxes" is checked, submit
if there's no selected checkboxes, show the alert message
if there's at least one checkbox (or 'n' checkboxes) selected,
submit
On the HTML view i have this:
<div class ="container-fluid">
<div class="row">
<div class="col-md-6">
<div class="cbx input-group">
<div class="checkbox" name="imtesting" ng-show="$ctrl.coupons.length > 0">
<label><input type="checkbox"
ng-show="$ctrl.coupons.length > 0"
name="allCoupons"
ng-model="$ctrl.all"
ng-click="$ctrl.selectAll()"/>Select all coupons</label>
<ul>
<li ng-repeat="c in $ctrl.coupons">
<input type="checkbox"
name="couponBox"
ng-model="c.Select"
ng-click="$ctrl.result()"
required/>{{c.CodeCoupon}}
<br>
</li>
</ul>
<label class="label label-danger" ng-show="submitted == true && !ctrl.newTest()">Select at least one coupon</label>
</div>
</div>
</div>
</div>
Hope you can help me.
Thanx in advance.
You can use the Select property from each coupon object like
vm.canSubmit = function() {
for(var i = 0; i< vm.coupons.length; i++)
{
if (vm.coupons[i].Select) {
return true;
}
}
return false;
}
Redo the way you are handling your selectsAll function. When you are using angular there is a thing called scope.$apply that is actually running which tells the dom to update if the object or properties have changed. Sometimes if you use for loops the way you are using them it wont register a change.
Try this and it should work:
vm.selectAll = function()
{
vm.all = !vm.all;
vm.coupons.forEach(function(o){
o.Select = vm.all;
})
}
vm.submit = function(){
var checked = 0;
vm.coupons.forEach(function(o){
if(o.Select === true)
checked +=1;
})
if(vm.all || checked > 0){
//submit here
}
else if(checked === 0){
//error
}
}
This will work both ways. If checked it will check all and if unchecked it will uncheck all. That validation will work for all three scenarios.

AngularJS ng-repeat with checkbox and filter

I have ng-repeat list, and I need to filter that list with checkbox. In checkbox I have three value, ERROR, WARNING, SUCCESS. If I check ERROR, show only error, if I check ERROR and WARNING show error and warning, same with success. But problem is, when I check ERROR box, list show only data with error, but when I check WARNING, they show all data in list, not only ERROR and WARNING data. For better explanation here is
> http://jsfiddle.net/ADukg/12574/
It's because of your toggleFilter() function
$scope.toggleFilter= function(filterValues) {
if ($scope.filterValue == undefined) {
$scope.filterValue = filterValues;
} else {
delete $scope.filterValue;
}
};
What is does:
When there is no filter, set the selected filter
When there is a filter, delete the current filter
So when you check ERROR, it sets ERROR as filter, but when you then click WARNING too, it triggers the else, and removes the current selection.
When you change your else to:
else {
delete $scope.filterValue;
console.log($scope.filterValue);
}
You can see it logs undefined when selecting more than 1 filter.
Because there is no any solution for this, here is my code how I fix this.
<div class="nav">
<div ng-repeat="filter in filters" ng-class="{sel: selection.indexOf(filterValue) == selected}">
<span class="filters_ct_status"></span>
<div ng-repeat="filterValue in filter.lists" style="float:left; padding: 5px">
<input type="checkbox" value="{{filterValue}}" ng-model="checked" ng-checked="selection.indexOf(filterValue) > -1" ng-click="toggleSelection(filterValue)">
<img ng-if="filterValue == 'Success'" src="assets/img/success.png" alt="success"/>
<img ng-if="filterValue == 'Warning'" src="assets/img/warning.png" alt="warning"/>
<img ng-if="filterValue == 'Error'" src="assets/img/error.png" alt="Error"/>
</div>
</div>
</div>
<div class="table_bench_info logBox" style="overflow-y: auto; height: 250px;">
<div class="list" ng-repeat="list in lists">
<span ng-if="listaFiltera.indexOf(list.class) !== -1">{{list.description}}</span>
</div>
</div>
and there is controller
$scope.filterValue = [];
// toggle selection for a given employee by name
$scope.toggleSelection = function(valueFilter) {
var idx = $scope.filterValue.indexOf(valueFilter);
if (idx > -1) {
$scope.filterValue.splice(idx, 1);
if($scope.filterValue.length == 0){
return $scope.listaFiltera = ['Error','Warning','Success'];
}else{
$scope.listaFiltera = $scope.filterValue.map(function(x) {
return x;
});
}
} else {
$scope.filterValue.push(valueFilter);
$scope.listaFiltera = $scope.filterValue.map(function(x) {
return x;
});
}
};
$scope.filters = [
{
lists: ['Error','Warning','Success']
}
];
We need push checked checkboxes to the array. And splice unchecked checkboxes from the array. Also, we need to check $scope.filterValue.length if we want multiple filters.

Categories

Resources