Question

I am completely new to Javascript and especially AngularJs. Here is my problem, I need to call ng-click function inside ng-repeat to hide a some html outside of it.

As I understand the problem is because all of the variables (in this case specifically variable "locations") is in another scope which I cannot access. Can anybody help me with the shortest way possible to go around this problem?

I have managed so far to almost finish my website with only angular html tags (meaning I didn't really have to write any custom functions) and this is the absolute last piece.

Also, as I understand whenever a new controller in angular is created, it has its own scope. In this case, all of the calls (besides the one that I am having problems with) have been made without initializing any of the controllers, so how do you access variables? Is there something like a "default Scope"? I know rootScope did not work for me.

Thank you in advance.

<div id="top_nav">
    <div id="top_nav_right">    
        <div id="page_header" ng-show="checked" ng-switch on="page">
        </div>  
        <a href="#" ng-click="checked = ! checked">
        </a>
    </div>      
</div>  
<div id="main_sidebar" class="check-element animate-hide" ng-show="checked">
    <ul class="menu" ng-show="!locations">
    </ul>
    <ul class="menu" ng-show="locations">
    </ul>
</div>

<div id="sub_sidebar" ng-show="checked" ng-switch on="page">
        <div ng-switch-default "check-element animate-hide">
                <div id="latest_trips_container">       
                    <div ng-controller="PostsCtrlAjax">  
                                <ul id="latest_trips" ng-controller="MyCtrl">   
                                    <li ng-repeat="post in travels">
                                                <div id="trip_details">
                                                    <a id="details" href="#/details" ng-click="locations =! locations"></a>
                                                </div>
                                    </li>
                                </ul>
                    </div>  
                </div>
        </div>              
</div>

Was it helpful?

Solution

You will have to create a controller surrounding both HTML fragments:

<div ng-controller="Ctrl">
    <!-- YOUR CODE HERE -->
</div>

The controller will define the locations property, but inside another object (let's call it viewState):

app.controller("Ctrl", function($scope) {
    $scope.viewState = {
        locations: false
    };
};

Then bind to the inner locations:

<ul class="menu" ng-show="!viewState.locations">
</ul>
<ul class="menu" ng-show="viewState.locations">
</ul>
...
<a id="details" href="#/details" ng-click="viewState.locations = !viewState.locations">

The reason for this, and why it didn't work for you with the $rootScope is how scopes inherit the properties of their parents through Javascript's prototypical inheritance. Roughly and really shortly:

When you read a property from a scope and that scope does not contain this property, JS will look at its prototype (again very roughly speaking, the scope's parent scope). The chain continues up to the $rootScope. So, putting locations in the $rootScope will result in successful reading of this property.

Whenever you write a variable to a scope, it is written directly to that scope, no matter where it was read from. So changing locations in the inner scope has no effect in the outer scope (e.g. $rootScope).

Putting the variable inside an object results in reading the object, which resolves to the correct scope, then writting the property to the correct object.

OTHER TIPS

This is what I ended up using. It seems extremely simple but maybe it will help others who are beginners as well. This is basically the code for making values accessible in different controllers. It is the same as Nikos suggested if I understood it correctly.

var myApp = angular.module('myApp',[]);

    myApp.value('Pages',{page:"My Profile"});
    myApp.value('Menu',{show:false});
    myApp.value('Menu2',{show2:false});

    myApp.controller('MainMenu', function($scope,Menu,Pages) {
        $scope.menu = Menu;
        $scope.pages = Pages;
    });

    myApp.controller('MainSidebar', function($scope,Menu,Menu2,Pages) {
        $scope.menu = Menu;
        $scope.menu2 = Menu2;
        $scope.pages = Pages;
    });

    myApp.controller('SecondSidebar', function($scope,Menu,Menu2,Pages) {
        $scope.menu = Menu;
        $scope.menu2 = Menu2;
        $scope.pages = Pages;
    });


    myApp.controller('TripsFx', function($scope,Menu2,Pages) {

        $scope.menu2 = Menu2;
        $scope.pages = Pages;
    })

This is what I do to have an accessible Rootscope.

Set up Rootscope in app.run: (Don't forget to inject $rootScope)

    var myApp = angular.module('ProGen', []);
    myApp.run(function($rootScope) {
      //setup Rootscope
      $rootScope.locations = false;
    })

Create a Controller with a function that changes Rootscope ($rootscope injected too)

    function someCtrl($rootScope, $scope) {
      $scope.travels = [
        {dest: 'Rome'},
        {dest: 'London'}
        ];

      $scope.flipMenu = function() {
        $rootScope.locations = !$rootScope.locations;
      }

    }

So this is the html:

    <html ng-app>
            {...}
    <body>
      <div id="main_sidebar">
        <ul class="menu" ng-show="!locations">
          <li>x1</li>
          <li>x2</li>
          <li>x3</li>
          <li>x4</li>
        </ul>
        <ul class="menu" ng-show="locations">
          <li>y1</li>
          <li>y2</li>
          <li>y3</li>
          <li>y4</li>
        </ul>
      </div>

      <div ng-click="locations =! locations">Change me (no Controller)</div>

      <div ng-controller="someCtrl">
        <ul>
          <li ng-repeat="post in travels">
            <div ng-bind="post.dest" ng-click="flipMenu()"></div>
          </li>
        </ul>
      </div>

    </body>

    </html>

And this is the JS:

  var myApp = angular.module('ProGen', []);
  myApp.run(function($rootScope) {
    //setup Rootscope
    $rootScope.locations = false;
  })

function someCtrl($rootScope, $scope) {
  $scope.travels = [
    {dest: 'Rome'},
    {dest: 'London'}
    ];

  $scope.flipMenu = function() {
    $rootScope.locations = !$rootScope.locations;
  }
}

You will find a working Plunker here: http://plnkr.co/edit/ygLlIoE55aI5q8Wkicc5?p=preview

Not sure if this what you wanted. But I hope it helps anyway. (Don't yell at me that this is against Angular Zen, because of reasons:-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top