2016-01-21 3 views
0

Я использую директиву для отображения div на экране только тогда, когда размер экрана меньше 600 пикселей. Проблема заключается в том, что значение области не обновляется, даже используя $apply() внутри директивы.Директива AngularJS не обновляет значение области даже при применении

Это код:

function showBlock($window,$timeout) { 
    return { 
     restrict: 'A', 
     scope: true, 
     link: function(scope, element, attrs) { 
      scope.isBlock = false; 
      checkScreen(); 

      function checkScreen() { 
       var wid = $window.innerWidth; 
       if (wid <= 600) { 
        if(!scope.isBlock) { 
         $timeout(function() { 
          scope.isBlock = true; 
          scope.$apply(); 
         }, 100); 
        }; 

       } else if (wid > 600) { 
        if(scope.isBlock) { 
         $timeout(function() { 
          scope.isBlock = false; 
          scope.$apply(); 
         }, 100); 
        }; 
       }; 
      }; 
      angular.element($window).bind('resize', function(){ 
       checkScreen(); 
      }); 
     } 
    }; 
} 

HTML:

<div ng-if="isBlock" show-block> 
    //..conent to show 
</div> 
<div ng-if="!isBlock" show-block> 
    //..other conent to show 
</div> 

Примечание: Если я не использую $ таймаут я получаю ошибку

$digest already in progress

Я консольные журналы внутри, чтобы проверить, обновляет ли оно значение, а внутри директивы все работает нормально. Но изменения не идут на представление. Блок не отображается.

+0

если вы хотите просмотреть данные отличаются в зависимости от размера окна, вы должны использовать CSS, как '@media экрана и (макс-ширина: 600px)' – Lusk116

+0

Я знаю об этом, но это будет используется для других purpouses, поэтому даже с базовым примером я буду расширять его позже. Кроме того, ng-if не отображает html, который в этом случае довольно обширен. – celsomtrindade

ответ

1

В таком случае вы должны использовать do rule, чтобы получить преимущество Prototypal Inheritance of AngularJS.

В принципе вам нужно создать объект, который будет иметь различное свойство. Как и в вашем случае, у вас может быть $scope.model = {}, а затем разместить в нем isBlock. Таким образом, когда вы находитесь внутри своей директивы, вы получите доступ к родительской области. Причина этого в том, что у вас есть scope: true, в котором говорится, что созданная в директиве прототипически унаследована от родительской области. Это означает, что все объекты ссылочного типа доступны в области вашего дочернего объекта.

Markup

<div ng-if="model.isBlock" show-block> 
    //..conent to show 
</div> 
<div ng-if="!model.isBlock" show-block> 
    //..other conent to show 
</div> 

Контроллер

app.controller('myCtrl', function($scope){ 
    //your controller code here 

    //here you can have object defined here so that it can have properties in it 
    //and child scope will get access to it. 
    $scope.model = {}; //this is must to use dot rule, 
    //instead of toggle property here you could do it from directive too 
    $scope.isBlock = false; //just for demonstration purpose 

}); 

, а затем внутри директивы, вы должны использовать scope.model.isBlock вместо scope.isBlock

Update

Как вы используете шаблон controllerAs внутри вашего кода, вам необходимо использовать scope.ag.model.isBlock. который предоставит вам доступ, чтобы получить значение переменной области видимости внутри вашей директивы.

В принципе вы можете получить значение родительского контроллера (используется шаблон controllerAs), чтобы получить доступное значение контроллера внутри дочернего. Вы можете найти объект с вашим псевдонимом контроллера внутри $scope. Как здесь, вы создали ag в качестве псевдонима контроллера, поэтому вам нужно сделать scope.ag.model, чтобы получить значение model внутри функции директивной ссылки.

ПРИМЕЧАНИЕ

Вам не нужно использовать $apply с $timeout, который может бросить ошибку $apply in progress, так что $ таймаут будет работать переваривать для вас, вам не нужно беспокоиться о том, чтобы запустить дайджеста.

Demo Here

+0

Невозможно контролировать все из директивы? – celsomtrindade

+0

@CelsomTrindade в вашем случае нет .. вы должны иметь atleast '$ scope.model = {};' define на вашем контроллере. –

+0

Даже если не использовать область: true? Потому что директивная функциональность - это только контроль. – celsomtrindade

0

Я подозреваю, что это связано с тем, что директива show-block не будет запущена, если ng-if = «isBlock» никогда не будет истинным, поэтому никогда не регистрирует событие изменения размера.

+0

Я заметил это после того, как задал вопрос. Затем я вставлял другой div с противоположным значением (см. Отредактированный вопрос), но проблема по-прежнему сохраняется. При использовании журнала я могу все время изменять размер. – celsomtrindade

+0

Объем: true означает, что isBlock до того, как директива находится в другой области, чем та, которую вы устанавливаете/изменяете в директиве. Попробуйте удалить это. – tanenbring

0

В моем опыте линейного кода никогда не работает хорошо с динамическими свойствами DOM, такие как окна калибровки. С кодом, который ищет размер экранов, вам нужно поместить его в какой-либо наблюдатель событий/DOM, например. в угловом я использовал бы часы $ watch, чтобы наблюдать размеры. Поэтому, чтобы исправить это, вам нужно разместить код в виде $ watch, например, ниже. Я не тестировал этот код, просто направленный. Вы можете смотреть $ window.innerWidth или вы можете смотреть $ element, например. тело зависит от вашей цели. Я говорю это, поскольку экраны будут повсюду, но если вы контролируете элемент DOM, например, тело, вам лучше управлять. также я не использую $ timeout для краткости.

// watch window width 
showBlock.$inject = ['$window']; 
function bodyOverflow($window) { 
    var isBlock = false; 
    return { 
     restrict: 'EA', 
     link: function ($scope, element, attrs) { 
      $scope.$watch($window.innerWidth, function (newWidth, oldWidth) { 
       if (newWidth !== oldWidth) { 
        return isBlock = newWidth <= 600; 
       } 
      }) 
     } 
    }; 
} 

// OR watch element width 
showBlock.$inject = []; 
function bodyOverflow() { 
    var isBlock = false; 
    return { 
     restrict: 'EA', 
     link: function ($scope, element, attrs) { 
      $scope.$watch($element, function (new, old) { 
       if (newWidth) { 
        return isBlock = newWidth[0].offsetWidth <= 600; 
       } 
      }) 
     } 
    }; 
} 
+0

хотя это синтаксическая ошибка, смотрите '$ element' почему? –

+0

Хороший улов, не поймал это, поскольку я взял его из некоторого кода моего переполнения текста элемента, где у меня есть контроллер, где я вставляю $ element – Nolan

+0

Понял концепцию, но 2 вопроса: -Как передать значение вид? Все еще не в состоянии это сделать. -Я прочитал несколько статей, говорящих, что использование $ watch - не лучшая практика для ng и может поразить производительность. Проект, над которым я работаю, довольно сложный, поэтому я стараюсь спасти везде, где это возможно. – celsomtrindade

Смежные вопросы