1

What I want is very simple, I want the Expand All button to be auto clicked when I open this pluralsight course page. Its HTML is:

<a id="expandAll"
   ng-click="expandAllModules()"
   ng-hide="allModulesExpanded()">
    Expand All
</a>

So it seems easy and we just need to call the function expandAllModules(). However I don't know why it give me undefined when I check its type:

typeof expandAllModules
=> "undefined"

Generally typeof a function should give me "function" like this:

function a(){}
=> undefined
typeof a
=> "function"

Since the function expandAllModules() is not available, I can't call it. Anyone can give me a hand on this issue?


Edit

Perhaps I need to elaborate on my question. I'm not the author of that page. I just want to make a simple greasemonkey or tempermonkey script and expand the modules automatically when I enter the page.

9
  • 1
    That's using Angular binding to call a function on the model. Commented Sep 30, 2014 at 2:30
  • you would have to check the $scope for that function rather than just the function I think. Commented Sep 30, 2014 at 2:30
  • the $scope is not available too. Commented Sep 30, 2014 at 2:43
  • It's not a normal function, it's an angular thing, and it doesn't exist. Angular just kind've uses the name, and then the name acts as an "id" that links with the id of a function, but the name of the function isn't the same as the id. You can still simulate this same thing though by doing synthesized events or just using click() Commented Oct 16, 2014 at 3:58
  • 2
    Well, what exactly are you trying to make? Are you just trying to do this in the javascript/developer console? Are you trying to make a browser extension? Or a bookmarklet? Commented Oct 16, 2014 at 4:00

3 Answers 3

4
+200

The Problem

The reason calling just expandAllModules() doesn't work is because this function belongs to one of Angular's scopes and isn't a method assigned to window. This function is defined in Plural Sight's table-of-contents-controller-v9.js like so:

"use strict";

pluralsightModule
    .controller("TableOfContentsController", ['$scope', ..., function ($scope, ...) {
        ...

        $scope.expandAllModules = function() {
            _.each($scope.courseModules, function (module) { module.visible= true; });
        };

        ...
    }])

The Solution

In order for us to call this function ourselves, we have to go through this scope.

scope is an object that refers to the application model. It is an execution context for expressions. Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events.
AngularJS: Developer Guide

The scope is part of the element which triggers the function. We can access this particular scope by passing the element's id attribute into angular.element(), then calling scope() on that object:

angular.element('#expandAll').scope()

This will give us the following data, where we can see the expandAllModules() function:

Console Example

Unfortunately AngularJS doesn't let us simply execute scope().expandAllModules(); instead we have to go through it's $apply and $eval methods:

var scope = angular.element('#expandAll').scope();

scope.$apply(function() {
    scope.$eval(scope.expandAllModules())
});

We can now also collapse the modules as well by calling:

scope.$apply(function() {
    scope.$eval(scope.collapseAllModules())
});

Working Screenshot

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your help! The system don't allow me to award your answer now. Will do it later.
1

I apologize if I am off-base here. Are you trying to "link" into that page and 'force' the page to "expand all", or do you have access to the page, and want to trigger the click with some code on the page, by you inserting the code? Just doing something like this seems to work from commandline.

   jQuery(function(){
      jQuery('#expandAll').trigger('click');
   });

Since I do not know your need, my thought is that this is a bit simplistic and not what you are looking for. From the responses of others, it appears you want to create your own directive to initiate the click?

Comments

1

I might have some typos -- but the idea is there.

angular.element(document.body).ready(function() {

    var el = angular.element( document.getElementById('expandAll') );

    var scope = el.scope();

    scope.expandAllModules();

    scope.$digest(); <--- might not be needed, but when i check your site, it needs to have this

});

updates

if it was just 'onclick' instead of 'ng-click', you do not need to get the scope; and just call the function directly.

updates

I have tried this on your site, you need to have scope.$digest(). When I tried it, i was using the developer console.

see the developer console below

I was playing with it on your site. enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.