简体   繁体   中英

Calling a scope variable outside of a directive

I am using juqeryUi draggable to drag a div around. I am storing the location that is was dragged to inside localStorage so that when the page is refreshed it is in the same location. What I am trying to do now is store the position inside a local variable and assign the values to another div.

Index.html

    <!DOCTYPE html>
    <html lang="en" ng-app="container">
    <head>
      <meta charset="utf-8">
      <title>efoli</title>

      <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
      <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
      <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
      <script type="text/javascript" src="js/angular.min.js"></script>
      <script type="text/javascript" src="containers.js"></script>

      <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
      <link rel="stylesheet" href="Style/design.css">
    </head>
      <body ng-controller="ContainerController as contain">

        <div id="grid" ng-hide="editing"></div>
        <div class="drag resize {{item.class}}" ng-repeat="item in block" id="{{item.id}}" ng-hide="editing" edit>
          <h1>{{item.title}}</h1>

  <!-- ------- Wont show anything--------- -->
          <h2>{{topPosition}}</h2>
          <textarea type="text" id="{{item.id}}" style="display:table-cell; width:inherit; height:inherit"></textarea>
        </div>
      </body>
    </html>

Containers.js

(function() {
  var app = angular.module('container', []);
  app.controller('ContainerController', ['$scope', function($scope) {
    $scope.block = [
      { "id" : "1",
        "class":"fname",
        "title" : "First Name",
        "text":""},
      { "id" : "2",
        "class":"lname",
        "title" : "Last Name",
        "text" : ""},
      { "id" : "3",
        "class":"education",
        "title" : "Education",
        "text" :""},
      { "id" : "4",
        "class":"contact",
        "title" : "Contact",
        "text" : ""},
      { "id" : "5",
        "class":"experience",
        "title" : "Experience",
        "text" : ""}
    ];
  }]);

  app.directive('edit', function(){
    return {
      restrict:'A',
      link: function($scope) {
        angular.element(document).ready(function() {
          var sPositions = localStorage.positions || "{}",
          positions = JSON.parse(sPositions);

          $.each(positions, function (id, pos) {
            $("#" + id).css(pos)
          });

          $('.drag').draggable({
            grid:[25,25],
            scroll: false,
            stop: function (event, ui) {
              positions[this.id] = ui.position
              $scope.topPosition = positions[this.id].top;
              $scope.leftPosition = positions[this.id].left;
              localStorage.positions = JSON.stringify(positions)
            }
          }); ...

In index.html when I call topPosition nothing populates. I ran a console.log inside .draggable() and I got the value of the top position but when I ran console.log outside of .draggable I got undefined. I'm guessing that the scope variable is just local but was wondering how can I make it global so I can use the values in different places.

Declare a scope variable in controller as,

$scope.topPosition = ""; //in the container controller

and assign topPosition value to that variable in directive by calling the variable using parent scope, like

var parentScope = $scope.$parent; // inside the edit directive

and inside the draggable,

parentScope.topPosition = positions[this.id].top;

this scope variable can be used in other events in directive and also in the controller.

Please find the modified PLUNKER . Hope it helps.

There is no scope issue here. The issue is that draggable is not something which angular is aware of, so the digest cycle is not invoked when we interact with the draggable .

You can fix this by invoking scope.$apply() or wrapping the code in something that invokes $apply() internally, like a $timeout . This is done to inform angular that something has changed and it needs to go check the watches and update the bindings.

You can see this in action in this plnkr . (Note that you need to make a drag since topPosition is only added to scope in it's stop event)


To Do (Learn and implement, read the docs ):

Now you can see that all the bindings has the same value, this is expected since they all share same scope. To fix this, you should use isolated scopes (Detailed explanation is out of scope of an answer).

Another things to note is that your directive is in an ng-repeat , so itll be invoked for each element, no need to use global selectors ( and you shouldn't be using global selectors in a directive ) like $('.drag').draggable() , it should be element.draggable() .

also link is called once the element is created, so no need of angular.element(document).ready( as well.

Also you should use getItem() , setItem() etc to interact with localstorage.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM