Angular ng-show doesn't work properly when value changes - javascript

I'm trying to show div depends on permission of log in user.
<div class="container">
<p> {{permission}}</p>
<div ng-show="permission" class="admin_panel">
....
</div>
</div>
and in controller, it is set:
$scope.init = function(){
if($window.sessionStorage.isAdmin){
$scope.permission = $window.sessionStorage.isAdmin;
}
$log.info("are you admin??? " + $scope.permission);
};
$scope.init();
In console, I could verify that permission was set to false and {{permission}} also showed
its value is false. However, ng-show is still showing even though the value is false. I'm not sure what's wrong with this.

Have you tried ng-show="permission === true;"? ng-show, to my understanding, is meant to evaluate whatever is inside the quotes. this would just explicitly state the evaluation. I've had experiences where just having a variable inside the quotes isn't an evaluation that ng-show recognizes for some odd reason.

I had a similar problem except that my variable was changed inside
a timeout function like this:
<div ng-show="check"> something .... </div>
setTimeout(function(){
check = false;
},500);
the problem was solved when i added $scope.$apply() inside timeout:
setTimeout(function(){
check = false;
$scope.$apply()
},500);

If you want to show or hide some content that depends of the user permissions, instead of using "ng-show", you should use "ng-if".
ng-show/ng-hide only adds or remove a CSS class that show or hide that element (display:none), but an user could change it easily in the browser.
Using ng-if: "If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM."
https://docs.angularjs.org/api/ng/directive/ngIf

I have a same problem and every thing work fine except ng-show. I missed something stupid. when you call a controller from different part of your document you can not share data between them. for example i have 2 div tag
in document
<div id="1" ng-controller="contentCtrl">
<div ng-click="toggleSidebarShow()">
<!-- some code here -->
</div>
</div>
<div id="2" ng-controller="contentCtrl">
<div ng-show="showSidebar">
</div>
</div>
showSidebar between contentCtrl of div 1 and div2 wasn't share.
in controller
// some code
$scope.showSidebar = true;
$scope.toggleSidebar = function (){
$scope.showSidebar = ! $scope.showSidebar;
};
but this code doesn't work because toggleSidebar called outside of the div2 tag and have it's own showSidebar. To conquer this problem you had to use service or modules. see this link to more information.

One more thing to check is when your page loads, in the inspect element check if the element you are trying to use ng-show on is rendered inside the element which has the ng-controller directive.
If your element with ng-show is outside the ng-controller element then ng-show wont work

Related

How do I removeAttribute() hidden from p2? doesn't seem to do anything as is

I'm trying to change the attribute of an object with removeAttribute to take away the hidden status of it but so far nothing seems to work.
My code seems to have no effect. Am I doing something wrong?
function changePage() {
document.getElementById.("p2");
p2.removeAtribute.("hidden") ;
}
I've also tried it all on one line as well like so
function changePage() {
document.getElementById.("p2").p2.removeAtribute.("hidden") ;
}
I've never seen the use of dots before opening parentheses.
E.g.
document.getElementById.("p2").p2.removeAtribute.("hidden") should be document.getElementById("p2").removeAtribute("hidden")
(You are also referencing the element by id after you just retrieved it, which is unnecessary.)
Your first example didn't work because you retrieved the element and did nothing with it, then tried to access a p2 variable that wasn't declared. Again, you also have the . before parentheses.
Here's the js example:
function changeVisibility()
{
var p2 = document.getElementById('p2');
switch (p2.style.visibility)
{
case 'hidden':
document.getElementById('p2').style.visibility = 'visible';
break;
case 'visible':
document.getElementById('p2').style.visibility = 'hidden';
break;
}
}
<div id="p2" style="visibility:hidden">
test
</div>
<br />
<button onclick="changeVisibility()">
change visibility with basic js
</button>
And here's the jQuery example:
function changePage()
{
$('#p2').toggle();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="p2" style="display:none">
test
</div>
<br />
<button onclick="changePage()">
change visibility with basic js
</button>
The basic JS version uses the visibility style, and you can see that it doesn't collapse the element, it only makes it invisible.
jQuery has a nice built-in .toggle function that changes the display of the element. If it is hidden, it collapses the element. When the element is displayed, it is re-assigned whatever the display style is for that element. Building that in basic js would take a lot more work, as you are then tracking state (if you want to make the method reusable). You can make jQuery work similarly to the basic js version if you use the css properties, but toggle is quite nice and simple.
Your main issue is that you were mixing the getting of the element with methods that are only available on jQuery objects. I suggest reading the jQuery tutorials for basic accessors, which can get elements by id, class name, etc.

Remove any specific html code using javascript

In the past I used Google Developer Console to delete some specific divs on a page. I could do it manually of course but in some cases where the divs where many I had to use the console. I had a single line code that did the job (I found it while searching the internet) but I lost my note.
So how can I delete using javascript any html code (by copy pasting the code).
Something like:
elements = $('<div ... </div>');
elements.remove();
OR
$('<div ... </div>').remove();
Any ideas? I am not an expert in javascript (obviously) and I've been searching stackoverflow for hours without finding anything that works.
UPDATE: I think some people might get confused with my question. Google developer console accepts javascript command lines. So even though I ask for javascript I will use the code on the google developer console.
UPDATE 2 :
Here is an example of a div I need to delete. Keep in mind I want to copy paste the entire code in the javascript code. Not just identify the div.
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
It's the data-entry-status="declined" that makes that div unique so I can't just identify the div using an id selector or a class selector. I need to put the entrire thing there and remove it.
I tried:
$('<div class="entry-status-overlay" data-entry-status="declined"><div class="entry-status-overlay__inner"><span class="entry-status-overlay__title">Declined</span></div></div>').remove();
It didn't remove the div.
Try to search the dom by its outerHTML.
function deleteDomByHtml(html){
html=html.replace(/\s/g,'');
$("*").each(function(){
if(this.outerHTML.replace(/\s/g,'')===html){
$(this).remove();
}
});
}
And try this line on this page:
deleteDomByHtml(`<span class="-img _glyph">Stack Overflow</span>`);
You cannot do by simply pasting the code. That will remove all the div element.
You may need a specific selector like id,class or child to specific parent to remove the element from the dom.
Consider this case the divs have common class but the data-entry-status is different. So you can get the dom using a selector and then check the dataset property.
For demo I have put it inside setTimeout to show the difference. In application you can avoid it
setTimeout(function() {
document.querySelectorAll('.entry-status-overlay').forEach(function(item) {
let getStatus = item.dataset.entryStatus;
if (getStatus === 'declined') {
item.remove()
}
})
}, 2000)
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div class="entry-status-overlay" data-entry-status="accepted">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">accepted</span>
</div>
</div>
Just add any attribute with [] and it will remove the element.
$('[class="entry-status-overlay"]').remove();
/*OR*/
$('[data-entry-status="declined"]').remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
function del(){
var h = document.body.outerHTML;
h = h.match('<div>...</div>');
h.length--;
return h;
}
I guess this will work just give it a try... i tried on browser console and it worked, this way you can match the exact you want.
I might as well add my take on this. Try running this in your console and see the question vanish.
// convert the whole page into string
let thePage = document.body.innerHTML,
string = [].map.call( thePage, function(node){
return node.textContent || node.innerText || "";
}).join("");
// I get some string. in this scenario the Question or you can set one yourself
let replacableCode = document.getElementsByClassName('post-layout')[0].innerHTML,
string2 = [].map.call( replacableCode, function(node){
return node.textContent || node.innerText || "";
}).join("");
// replace whole page with the removed innerHTML string with blank
document.body.innerHTML = thePage.replace(replacableCode,'');
If you want to identify divs with that particular data attribute, you can use a data-attribute selector. In the example below, I've used a button and click event to make the demo more visual, but in the console the only line you'd need would be:
$('div[data-entry-status="declined"]').remove();
$(function() {
$("#testbutton").click(function() {
$('div[data-entry-status="declined"]').remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div id="x">Some other div</div>
<button type="button" id="testbutton">Click me to test removing the div</button>
See https://api.jquery.com/category/selectors/attribute-selectors/ for documentation of attribute selectors.
P.S. Your idea to paste some raw HTML into the jQuery constructor and then execute "remove" on it cannot work - you're telling jQuery to create an object based on a HTML string, which is, as far as it's concerned, a new set of HTML. It does not try to match that to something existing on the page, even if that exact HTML is in the DOM somewhere, it pays it no attention. It treats what you just gave it as being totally independent. So then when you run .remove() on that new HTML...that HTML was never added to the page, so it cannot be removed. Therefore .remove() has no effect in that situation.

Why does div with ng-if prevent its sibling from running Angular?

I have just spent hours trying to discover why the Angular in one div suddenly stopped working. I finally tracked it down to a sibling div which has an ng-if="someVar". Currently someVar is true and the div displays and functions properly, including some ng-mouseovers, some ng-clicks and plenty of live updating scope {{variables}}.
However for some reason having this ng-if there causes its sibling's functions to completely stop functioning. {{otherVars}} just remain completely static and all ng-mouseovers and ng-clicks just completely stop doing anything. Why the heck is this happening??
This is a compacted version of my code:
<div class="first-div" ng-if="!showFAQ">
<p class="title">
<span ng-mouseover="message = messages.default; defaultHover = true" ng-mouseleave="defaultHover = false">{{defaultHover}}</span>
</p>
<span class="enter-button-inner" ng-mouseover="defaultHover = true; message = messages.enterButton" ng-mouseleave="defaultHover = false" ng-click="enterApp()">
Click here to start
</span>
</div>
<div class=" second-div show-message-{{defaultHover}}">
{{message}}
</div>
All the Angular directives and functions in the first-div work perfectly, whereas all the code in the second-div simply doesn't work at all.
Why is this?
Build Understanding:
ng-if will remove elements from DOM. This means that all your handlers or anything else attached to those elements will be lost. For example, if you bound a click handler to one of child elements, when ng-if evaluates to false, that element will be removed from DOM and your click handler will not work any more, even after ng-if later evaluates to true and displays the element. You will need to reattach the handler.
ng-show/ng-hide does not remove the elements from DOM. It uses CSS styles to hide/show elements (note: you might need to add your own classes). This way your handlers that were attached to children will not be lost.
ng-if creates a child scope while ng-show/ng-hide does not
Depending on what you want to achieve, you might want to use ngShow instead.
The difference with ngIf is that ngIf completely removes your element from the DOM, where ngShow just hides it. When ng-if evaluates to true again, it creates a clone of your element and adds it back to the DOM.
Seems like your setting scope variables in the <div> is failing (probably due to primitives in `ng-if's scope).
<div class="first-div" ng-if="!model.showFAQ">
<p class="title">
<span ng-mouseover="hoverHndl(true, messages.default)"
ng-mouseleave="hoverHndl(false)">Hover me!: {{defaultHover}}
</span>
</p>
<span class="enter-button-inner"
ng-mouseover="hoverHndl(true, messages.enterButton)"
ng-mouseleave="hoverHndl(false)"
ng-click="enterApp()">
Click here to start
</span>
</div>
<div class=" second-div show-message-{{defaultHover}}">
message: {{message}}
</div>
And JS:
$scope.showFAQ = true;
$scope.messages = {
default: "defaulMsg",
enterButton: "enterButton"
};
$scope.message = 'initialMsg';
$scope.hoverHndl = function(hover, message) {
$scope.defaultHover = hover;
$scope.message = message;
};
See it is working here if you do the assignment in a function: https://jsbin.com/lahoyevuqo/1/edit?html,js,output

AngularJS $scope variable does not go into view

I have a simple boolean variable that switches a DIV to be hidden at startup and then shown after an action until the end of the application. But it does not switch - the DIV is always hidden. Please help, what is wrong in the code below:
<div class="right" ng-controller="EmployeeDetailsCtrl" ng-show={{showEmployeeDetails}}>
<p>{{employee.name}} {{employee.surname}}</p>
</div>
inside EmployeeDetailsCtrl controller:
$scope.$on('showEmployee', function (event, data) {
$scope.showEmployeeDetails = true;
$scope.employee = data;
});
$scope.showEmployeeDetails = false;
BTW, the $scope.employee variable updates correctly after the event is triggered, so I'm really stuck what's going on here.
Remove the {{}} from your ng-show, like so:
<div class="right" ng-controller="EmployeeDetailsCtrl" ng-show="showEmployeeDetails">
<p>{{employee.name}} {{employee.surname}}</p>
</div>
When you're using ng-show you're binding to an expression, not a string, so just use:
ng-show="showEmployeeDetails". That's why you can do more complex stuff like ng-show="1 + 1 === 2".
If that still doesn't cut it, it could be a scoping issue with primitives being assigned to a child scope and not seen up the parent scope. It doesn't look like it from the code you showed but perhaps it's simplified for this question, you never know.

AngularJS update ng-init on change

Is there a way in which ng-init will get updated when tableCells will change ? I want to use this approach (or similar) so angular won't have to call findCellsByDate two times.
I also tried to change ng-init with ng-bind or ng-model, but bind will show [object Object] and model will throw an error as there isn't an attribution.
<span ng-init='cells = findCellsByDate(tableCells, day)'>
<div class='text' ng-show='forecastAndActualForCellsAreNotEmpty(cells)'>
<span ng-bind='getTotalHoursPercentageForCells(cells)'></span>
<span>%</span>
</div>
</span>
I don't think ng-init works that way, so what I'm thinking is that you should change some of your controller/model code to hold a boolean for forecastAndActualForCellsAreNotEmpty which would get updated.
On the other hand you could do it by css. I assume that if forecastAndActualForCellsAreNotEmpty returns false, getTotalHoursPercentageForCells would return 0. So you could bind that to a data attribute and using a css rule make the div go away. But in order to not use ng-init you would have to take the content also with css. And the only way to do that, that I know of, is with :before and :after.
Something like
<div class='text' data-percentage='{{getTotalHoursPercentageForCells(findCellsByDate(tableCells, day))}}'>
</div>
And the css
div[data-percentage=0]{
display: none;
}
div[data-percentage]:before{
content: attr(data-percentage) "%";
display: block;
}
Now I wouldn't use :before or :after to display actual application content, but rather things that are related to style. So I suppose the final recommendation would be to alter the model instead.
You can put the logic that changes the cells variable inside a watch function that observe changes in tableCells variable
$scope.$watch('tableCells', function(tableCells) {
if(!tableCells) return;
$scope.cells = findCellsByDate(tableCells, $scope.day);
});
In this way you keep that logic in the controller

Categories