toggle skips/misses 2nd sidebar - angularjs

Today's bogglement! I have two sidebars and a main content area. When I click on a button to expand the page, the sidebars should go away and the main content area spreads to 100%. (I'm trying to do something like what quandl.com does in its api displays, which is totally nifty.)
This should be really simple! I just add a class of 'apponly', which set the main-content to 100% and the sidebars to display:none. In my controller, I've got:
$scope.toggle = function() {
$scope.displayed = !$scope.displayed;
}
and in my html, I've got basically:
<div class="sidebar left" ng-class="{'apponly' : displayed }">
--something something--
</div>
<div class="main-content" ng-class="{'apponly' : displayed }">
<button class="btn btn-info device" ng-click="toggle()">[icon]</button>
--something something--
</div>
<div class="sidebar right" ng-class="{'apponly' : displayed }">
--something something--
</div>
...but it consistently only applies the class 'apponly' to the first sidebar and main content, and leaves the second sidebar intact (wrapped around to the next line, but still right there, w/no class of 'apponly' applied).
I tried to set up a plnk (http://plnkr.co/edit/ER4TPGexGnZ8knb4ThXQ?p=preview) but it won't work at all [okay that was a stupid oversight, now it does work except now I'm even more confused]. What really simple obvious thing am I totally missing here?
many thanks in advance!

AS PSL said, juste update your plunkr to <body ng-app="app" ng-controller="mainController"> and it will work. It actually does what you were expecting, so the issue is probably somewhere else.

Welp, I might as well answer since I (sort of) figured it out, and you never know, I might not be the only one baffled by such behavior.
It's tied to the animation. If you take the animation away, then everything behaves. You add it back in, and things get wacky again.
Why is this? I have no idea. But when I took the animation off the sidebars (so they simply disappear immediately), then the right-hand sidebar doesn't get pushed to the next line and end up remaining despite the added-class that should make it disappear. From behavior at least, it seems that the browser is trying to render animation at the same time the css-class is trying to make the section disappear. Which doesn't make any sense, b/c this works fine in other places, but all I know is that if you leave the animation on the main (middle) part, and turn it off on the sidebars, then everything behaves properly.
I'm not counting this as an answer, though, since it's more of a "well, that fixed it, if inadequately," which is less of an answer and more of a workaround left here for posterity, the enlightenment of any confused devs behind me, and the entertainment of any senior devs wandering through.

Related

How to click on a deeply buried button in div classes via protractor. No id

I am trying to click a button that is buried in div classes in the code via protractor.
I am pioneering a protractor project for my work and have reached a point where I no longer know what to do. I have a button that is buried in div classes and is not allowing me to click. I have tried using mouseMove to get over to the coordinates of the button, I have tried using the className of the specific button, etc. The button does not have an id. The id is not the issue as I have tried clicking a different button, equally buried in divs, by it's id. I need to know how to get through the layers of divs in order to click the button because the rest of the tests will be dependent on it.
APPLICATION CODE:
::before
<dashboard-label>
<div class="att-topic-analysis-tabs">
<div class="att-button-group">
<button class="btn btn-default btn-lg att-close-topic ng-scope"
role="presentation" tabindex="-1"
ng-click="removeTopic(currentTopic.id)" translate>
Close Topic
</button>
</div>
</div>
PROTRACTOR TEST:
it('Closes Topic Successfully', function(){
//opens the first available topic
openTopic.click();
//checks that the URL contains 'topics' after 5 seconds
browser.wait(proExpect.urlContains('topics'), 5000);
var closeTopic = element(by.className('att-close-topic'));
//browser.wait(proExpect.elementToBeClickable(closeTopicButton), 5000);
console.log(closeTopic);
closeTopic.click();
browser.wait(proExpect.urlContains('home'), 5000);
});
As you can see, the Close Topic button is kind of buried in div classes and the standard click isn't working. Any info would be greatly appreciated
If the closeTopic locator is finding the element, but failing to click it, check to make sure there's only one matching element in the DOM, and that it's visible. My favorite way to check the DOM is just ctrl-F in Chrome inspector and paste the exact CSS that the test is using (.att-close-topic). And to check that what it's getting is visible, use
console.log(closeTopic.isDisplayed());
This can be a big gotcha in protractor, because it doesn't fail (only warns) when there are multiple matches on the page, and it defaults to the first match rather than the first visible match, which drives me nuts, because it's very rare that you want to do anything with a non-visible element on the page.
This will be partly opinion, but just to add a layer to the conversation...
Sometimes the solution to locating a troublesome element on the page is to go back to the developers and make the page more testable. I've seen testers spend hours or days crafting brilliant workarounds to access a stubborn element, and the end result was a fragile, complicated end-to-end test (and aren't they fragile enough already?).
Sometimes a 5-minute conversation with a developer can result in a quick change in the production code (e.g. add a unique ID) that avoids all that effort and yields a much better result, more stable, more simple. But this requires open conversation between the dev and test team, and a culture that values testing as a primary activity enough to make those testability changes to production code that is otherwise working just fine.
This is what you want to read to help you debug why your test doesn't work.
Also, you might want to start adopting await/async since the control flow will go away in the future.
http://www.protractortest.org/#/debugging
try this
var closebutton=element(by.css("[ng-click="removeTopic(currentTopic.id)"]"),
EC = protractor.ExpectedConditions;
Waits for the element to be clickable.checks for display and enable state of button
browser.wait(EC.elementToBeClickable(closebutton), 10000);
now use : closebutton.click();

Angular not updating list fast enough

I have a list of 'cards' that when a filter is selected on the left side of the screen, the cards shown in the middle of the screen will update accordingly. Here is a snippet of the js:
$scope.isReady = false;
// This is an async method to retrieve from DB
AssignmentManagerService.getAssignmentsForClass(teacherId, classId).success(function(response) {
var instances = response.instances;
$scope.assignmentListData = instances;
$scope.isReady = true;
});
And here is a piece of the template:
<div flex class="item-list" ng-if="isReady">
<md-card ng-repeat="assign in assignmentListData track by assign.instanceId"
ng-click="selectCard(assign)"
class="item-list-item"
style="font-size:16px;"
ng-class="getCardClass(assign)"
ng-style="getCardStyle(assign)">
<div>
<span style='font-weight:500'>Title</span>: {{assign.title}}
</div>
<div style="margin-top:10px;">
<span style='font-weight:500' ng-if="assign.availableDate">Available Date:</span> {{assign.availableDate | date:'fullDate'}}
<span style='font-weight:500' ng-if="assign.createDate">Create Date:</span> {{assign.createDate | date:'fullDate'}}
</div>
</md-card>
</div>
One of two things will happen: I will either get two sections of cards on top of each other, one section with the old selection and one section with the new selection, for a half second before the old selection is removed OR the cards will all be integrated before the old cards are removed. All of this happens within the time span of a second but looks very unprofessional and ugly.
What is supposed to occur is the user makes a filter selection, the cards immediately hide, the new data is retrieved, and the new cards are shown. No overlapping, no multiple groups.
Here's what I have done:
Wrapped the async method/success into a $timeout function: Didn't work. Same results.
Wrapped the async method/success into a $scope.$$postDigest function: Didn't work. Same results.
Added a 400ms thread sleep in the back-end: While it does work, I'm not inserting a back-end fix for a front-end problem.
Tried various combinations of ng-if/ng-show on the div and the md-card: Didn't work. Same results.
The template was originally ~500 lines. I have stripped out all the extraneous markup except for this card bit to see if it was the digest cycle taking too long. Didn't work. Same results.
Any help would be greatly appreciated. Thanks!
Wow. My coworker and I just found some really old and buried CSS animations that were affecting the list in question. After removing them, everything works as it should. Doh! I'd like to thank #The.Bear and #JBNizet for pointing me in the right direction on this!

Odd issue with ng-show always evaluating to true

I had a bit of code in my view that would only show up when a particular value was true. Lt looked like this:
button type="button" ng-click="attachBarCode('enter')" ng-show="barcodeAllowed.status">Foo</button>
This was working until recently. My controller had some logic where, based on Ajax data, it would set $scope.barcodeAllowed.status to true. All of a sudden though, the button was always showing up. To help debug the issue, I added some additional tests to my view:
first test, <span ng-show="!barcodeAllowed.status">DONT SHOW</span><br/>
second test, <span ng-show="barcodeAllowed.status">DONT SHOW</span><br/>
test -{{barcodeAllowed.status}}-end -{{!barcodeAllowed.status}}- -{{barcodeAllowed | json}}-<br/>
test if <span ng-if="barcodeAllowed.status"> if was true</span><p>
Here is where things got crazy. Both "DONT SHOWS" rendered in my view, even though it seems as if that would be impossible. When I output the values in the third line, I saw false and true, as I expected.
Finally - the ng-if? It worked perfectly! The value did not show up.
I've heard folks mention that ngShow can have scope issues inside a ngif, but my code isn't inside an ngif.
So, you won't believe what it was. I was using a Content Security policy in my app and on a whim, I disabled it. As soon as I did, it began working. I played around a bit and discovered that I needed to add 'unsafe-eval' to the to the script-src area of my CSP in order for Angular to be able to apply the styles.
The Ng-show/Ng-hide directives needs a css-class to show/hide, since it just adds a class to your element when the scope-variable is truthy/falsy.
Ref: https://docs.angularjs.org/api/ng/directive/ngShow

Show directive as result of a click

I want to show content that comes from a directive when the user clicks on a link.
<li>Show popup</li>
Obviously I'm new to angularjs. I know the approach above doesn't make sense really but I was also trying to imagine how this might be done with ng-if but not coming up with anything. Any ideas? Thanks!
Edit 1: The directive that I want to use is:
<ng-pop-up></ng-pop-up>
That's part of ngPopup.
Edit 2: This is now resolved. It turns out that in the case of ngPopup, you put the directive somewhere, then you open the dialog using the open method, so I really didn't take advantage of the solutions given here. Giving Martin credit because his solution solves problem originally stated. Thanks all.
Not exactly sure what you are looking for.
When you say, content from a directive, is this an existing directive, or do you think the content should come from a directive?
In your example where you have show popup, do you mean you would like to have a dialog displayed when you click the link?
Or do you just want something like the following example?
angular.module('app', []);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app=app>
<a href="#" ng-click='showMessage = true'>Click Here</a>
<div ng-show="showMessage">Your Message Here</div>
</div>
Try looking at using ng-if (AngularJS docs). You can use a boolean in your scope to that is toggled by the ng-click.

Detecting page scroll/ current section being viewed in AngularJs

My page is divided into sections : #page-1 and #page-2
See Plnkr: http://plnkr.co/edit/RZJLmsWDfs63dC0QuDJi
<body>
<section id="page-1">
This is page 1. It takes the whole height of the browser. User has to scroll down to see page-2.
</section>
<section id="page-2">
<span class="animated bounce">This is page 2 </span>
</section>
</body>
Animation classes are being applied to different elements in #page-2.
However by the time the user scrolls down to these elements, the animation has already finished. Hence they just look like static objects.
Is there anyway I can detect when #page-2 is currently being viewed and then call a function to addClass('animated bounce') to certain elements ?
I would like to achieve this in angularjs if possible
I have found a angularjs directive that is probably helpfull for you in this case. Inview tries to solve this exact problem by reporting to you if a dom element is visible on the screen. Unfortunately I have been unable to test my solution because I couldn't find a minified js file of Inview but I assembled some code that should work:
<section id="page-2" in-view="{$inview ? isFocused=true;}">
<div ng-class="{'animated bounce': isFocused}">This is page 2 </div>
</section>
The $inview is supposed to be true whenever the element is in visible in the browser. This leads to the scope variable isFocused being set to true and therefor the animation class is added to your div.
This should work as you have intended in your question, if it does not work for some reason please let me know so I can improve my answer.

Resources