Ответы пользователя по тегу Angular
  • А расскажeте про promise и $resource?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Первое — чтобы преобразовать ангуларовский объект (в котором есть всякие одно- и двудолларовые параметры, все эти $xxx и $$xxx) в нормальный (т.н. raw json) нужно использовать стандартные ангуларовские методы из коробки:
    angular.fromJson(response)
    и
    angular.toJson(response)

    Просто поковыряйте эти функции и посмотрите, что они вернут.

    По поводу промисов. Когда вы вызываете какой-либо $resource-метод, например, .query(), то вам сразу же, моментально, возвращается объект с двумя параметрами — $promise и $resolved: false. После того, как ресурс получил данные, в ваш объект с двумя параметрами добавляется ещё куча данных (ну, json-данные, что вам вернул сервер), а параметр $resolved становится true.

    Так вот $promise нужен тогда, когда после загрузки данных вам нужно что-то сделать :) Ведь когда вы послали запрос, вы не знаете, когда придет ответ, а $promise знает и позволяет вам что-нибудь сделать именно после загрузки. Обращаться к промису нужно так:
    vm.data = dataService.getData().$promise.then(success, error);
    
    function success(resource) {
        // тут не данные в resource, а объект $resource с данными, тут можно почистить его через angular.fromJson и т.п.
    }

    Тут, после получения данных, ваш vm.data сразу же пополняется данными ответа (и вы там что-то выводите через ng-repeat — Ангулар там сам понимает, что выводить нужно только ваши данные, и не выводит еще два параметра $promise и $resolved, хотя они в объекте присутствуют, как вы уже в console.log вывели и убедились), а в функции success можно еще что-нибудь сделать.

    Можно так же сразу и не присваивать vm.data ничего, а сначала сделать какие-то действия в success и только потом присвоить, вот так:
    dataService.getData().$promise.then(success, error);
    
    function success(resource) {
        // тут не данные в resource, а объект $resource с данными, тут можно почистить его через angular.fromJson и т.п.
        // сначала что-нибудь делаем с полученными данными, а потом присваиваем их в скоуп
        vm.data = transformMyData(resource);
    }
    Ответ написан
    4 комментария
  • Почему не срабатывает обновление данных в AngularJS?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Ангулар ничего не знает о клике, повешенном через метод .on() — поэтому после клика Ангулару нужно принудительно сообщить об рефреше скоупа:

    a.on('click', function(e) {				
        var page = e.target.text;
    
        $scope.setPage(page);
    
        // обновляем скоуп
        $scope.$apply();
    });


    По поводу вообще всего в общем:

    В контроллере должна быть только логика — забудьте про жиКвери, забудьте про селекторы, выкиньте из головы жиКвери-подход — контроллеры ничего не знают о DOM-элементах, в контроллерах только логика.

    Прятать/показывать элементы нужно не по-жикверевски, через метод .css() (работая с DOM), а по-ангуларовски, через ng-show (работя с логикой).

    Задавать классы нужно не по-жикверевски, через метод .addClass() (работая с DOM), а по-ангуларовски, через ng-class (работя с логикой) (причем, ты задаешь классы .show/.hide — тут не классы нужны, тут используй ng-show, ведь ты же показываешь/прячешь).

    Вставлять элементы в DOM не нужно, это делается прямо в ХТМЛе, а не в контроллере:
    <ul class="pagination">
        <li ng-repeat="page in pages">{{page}}</li>
    </ul>


    Вешать события на элементы нужно не по-жикверевски, а прямо в ХТМЛе:
    <ul class="pagination">
        <li ng-repeat="page in pages" ng-click="openPage(page)">{{page}}</li>
    </ul>


    Да и вообще, там должна быть обычная ссылка, а не событие клика:
    <ul class="pagination">
        <li ng-repeat="page in pages">
            <a ng-href="/page/{{page}}">{{page}}</a>
        </li>
    </ul>


    И самое главное — удалите жиКвери. Он не нужен вообще-привообще, выкиньте из мозга саму концепцию жиКвери, выкиньте способ размышления на жиКвери — Ангулар работает совершенно по-другому.
    Ответ написан
  • Могу ли я с помощью angular присвоить переменной значение в html странице и далее работать с ней в контроллере?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Да, можете, но это называется... говнокод. Ни в коем случае нельзя логику выносить из контроллера в шаблон (о, ужас) — так делают только говнокодеры, это так и никак иначе.
    Ответ написан
    Комментировать
  • Почему не работает код в angular?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Потому, что вы обнулили объект:
    this.newUser = {};
    Объекты в JS копируются по ссылке — если вы в одном месте что-то поменяли, то и в других местах объект изменится. Перед тем как вставлять объект в массив users нужно его клонировать.

    (P.S. В table не должно быть нетабличных элементов — неправильно делать form внутри tbody. )
    Ответ написан
    2 комментария
  • Как сделать чтобы курсор мыши не реагировал на прозрачные участки изображения?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Жесть. При чем тут Ангулар? Вы думаете, что Ангулар еще и кашу умеет варить? Фреймворки реализуют архитектуру приложения, они не знают, что такое «прозрачные участки у изображения», когда день рождения у Анжелины Джоли и изберут ли Путина на третий срок — вы совершенно не понимаете даже о чем спрашиваете.

    И суть вашей проблемы тоже не понимаете — вам не прозрачные участки изображения нужно обрабатывать, совершенно мимо, вообще не то. И даже Яваскрипт здесь не при чем, вообще-привообще!

    Вам нужно через обычный CSS сделать border-radius нужной величины и задать background-image с картинкой и сделать background-size: cover; и background-position: center center;, а изображение не нужно делать круглым, изображение обычное, прямоугольное делайте, ибо скругление делается средствами CSS.
    Ответ написан
    7 комментариев
  • Как в Angularjs отобразить все данные из массива кроме данных из другого массива?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Ангулар тут не при чем вообще.

    У вас есть массив студентов, у каждого студента в данных есть индикатор, добавлен ли студент в какую-либо группу или не добавлен — типа, group_id: айдишка группы или null. Вот и фильтруйте по этому параметру.

    Либо сделайте два массива, для каждой таблицы свой, и с двумя массивами работайте — удаляйте/добавляйте.
    Ответ написан
    Комментировать
  • Как в $routeProvide прописать url если он постоянно меняется?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    reloadOnSearch: false (документация)
    Ответ написан
    Комментировать
  • Почему не работает ng-click в ng-repead - Angular?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    То, что вы прямо в ХТМЛ-коде пишете логику — гиперужасное дилетантство. На ng-click должна быть повешана функция, и уже в контроллере нужно писать логику, присваивать какие-то переменные и прочее, но ни в коем случае не в шаблоне, ибо получается уродское месиво.
    Ответ написан
    Комментировать
  • Как мне присваивать определенный класс в зависимости от страницы?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    В первом комментарии всё верно и лаконично сказали — через $rootScope — я же просто разжую.

    Модуль ngRoute это просто обычный конфиг — вы в этот конфиг можете пихать всё, что вам угодно. Задайте каждой страничке уникальную айдишку или название категории странички:

    app.config(['$routeProvider',
      function($routeProvider) {
        $routeProvider.
          when('/main', {
            id: 'main',
            title: 'Главная',
            category: 'rootPage',
            templateUrl: 'mainPage.html',
            controller: 'MainPage',
          }).
          when('/powerSky', {
            id: 'powersky',
            title: 'Всем повер-скай, посоны',
            category: 'contentPage',
            templateUrl: 'template/powerSky.html',
            controller: 'PowerSky'
          }).      
          otherwise({
            redirectTo: '/main'
          });
      }]);


    Теперь, при каждой смене странички, в основном контроллере (это который общий для всех страниц сайта) пихайте в $rootScope конфиг текущей странички (текущего роута) в параметр page:

    app.controller('MainController', function($rootScope) {
      $rootScope.$on('$routeChangeSuccess', function(e, current, previous) {
        var page = current.$$route;
    
        // присваиваем глобально
        $rootScope.page = page;
      });
    });


    Теперь в HTML-шаблоне вставляйте класс для BODY:

    <!DOCTYPE html>
    <html ng-app="app">
        <head>
            <title>{{page.title}}</title>
        </head>
        <body ng-class="page.id" ng-controller="MainController">
            <main ng-view></main>
        </body>
    </html>


    Или, если у вас странички разбиты на некие общие категории, то не айдишку вставляем, а название категории (тогда меньше всяких классов нужно будет писать в CSS):

    <!DOCTYPE html>
    <html ng-app="app">
        <head>
            <title>{{page.title}}</title>
        </head>
        <body ng-class="page.category" ng-controller="MainController">
            <main ng-view></main>
        </body>
    </html>


    Ну и в стилях будет:

    body {
        &.rootPage {
            background-color: #fff;
        }
    
        &.contentPage {
            background-color: #ddd;
        }
    }
    Ответ написан
    Комментировать
  • Как использовать несколько $index во вложенных ng-repeat для angular.js?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Несколько $index'ов делаются так и никак иначе (всё остальное это какой-то ужас отвратный):

    <ul>
        <li ng-repeat="(i, items) in collection">
            <ul>
                <li ng-repeat="(j, item) in items">
                    {{i}} — {{j}}
                    Чекбокс: <input type="checkbox" name="field[{{i}}][{{j}}]">
                    <button ng-click="doSomething(i, j)">Клацнуть</button>
                    <button ng-click="buyItem(item.id)">Купить</button>
                </li>
            </ul>
        </li>
    </ul>


    Что же касается вашего вопроса о покупке, то покупать и фиксировать выбранный товар нужно не по индексам гатегории и подкатегории (это абсолюто неправильно), а по айдишке товара.
    Ответ написан
    2 комментария
  • Как в kendo grid передать данные со скоупа?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    С — Скойп :)
    Ответ написан
    Комментировать
  • Как добраться до объекта?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Так же, как и внутрь любого другого, просто через точку — два знака доллара в названии параметра вас не должны смущать.

    var deferred = $q.defer(); // допустим, вы получаете промис из $q (а может быть из $http или $resource, я не знаю)
    console.log(deferred.promise); // возвратит объект, и там будет ваш $$state
    console.log(deferred.promise.$$state); // возвратит то, что внутри $$state
    console.log(deferred.promise.$$state.status); // возвратит status

    Как уже подметили комментаторы, если вы хотите это сделать, то вы делаете что-то не так, явно.
    Ответ написан
  • Как работает Require.JS?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Если вы используете AngularJS, то RequrieJS вам не нужен вообще никогда.

    1) Если вы делаете жирного клиента (т.е. все скрипты минифицируете в один-два файла, например: components.js (в котором AngularJS, LoDash.js и прочие библиотеки/плагины), application.js (собственно, ваша аппликация: контроллеры, директивы и прочее) и templates.js (все ХТМЛ-шаблоны для директив и страничек)), то вам RequireJS не нужен вообще — он просто бесполезен, так как асинхронно подгружать модули вам больше не нужно, ведь у вас и так всё есть, а Dependency Injection уже есть в Ангуларе из коробки.

    2) Если же вы используете Ангулар и для Dependency Injection хотите использовать еще и RequireJS, то это, конечно же, бред, не делайте так — в Ангуларе всё уже есть для DI.

    3) Если же вам нужна асинхронная подгрузка модулей, то используйте именно асинхронный загрузчик, без функционала DI (например, https://github.com/ded/script.js, да тысячи их) + Ангуларовский angular-loader.js, который позволяет загружать ангуларовские модули в любом порядке.
    Ответ написан
    Комментировать
  • Как добится мультиязычной маршрутизации в angularjs?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Изящного решения не предложу и на вопрос не отвечу, но оставлю здесь свой комментарий, для истории :)

    Хочу отговорить вас делать такую маршрутизацию — совершенно не обязательно загрязнять УРЛ данными о языке (особенно писать /en, когда у вас домен .com — это же и так обычно английский; или писать /ru при домене на .ru — там же и так русский обычно). Посмотрите на любой многоязычный сайт — там нет языка в адресной строке ни в каком виде, это уже прошлый век. (Исключение состовляют только огромедные сайты, где не только язык интерфейса разделен, но и сам контент и даже поиск по нему — например, Википедия).

    При заходе пользователя на сайт, берете язык из куков или определяете его язык (это делается средствами браузера — navigator.language и иже с ним) и сохраняете полученный язык в куках. Загружаете файл-локализации. Всё. Если пользователь нажал на другой язык, то сохраняете его в куках и подгружаете другой файл локализации.

    При последующих заходах язык уже будет известен, а подгрузку файла локализации можно ускорить, храня его в localStorage.

    Так же запаритесь каждый раз при вызове, например, $location.path(...), передавать туда еще и текущий язык. И сам конфиг роутов у вас будет выглядеть неизящно:

    $routeProvider
            .when('/:lang/about',
                {
                    templateUrl: 'pages/about.html',
                    controller: 'AboutController'
                })

    и так каждый роут.

    Ну и еще, а если пользователь ручками наберет адрес раздела в адресной строке и забудет язык указать (наберет просто mysite.com/about, а не mysite.com/ru/about), то что, приложение не будет работать?

    А для локализации используйте Angular Translate.
    Ответ написан
    4 комментария
  • В чём различия setTimeout и $timeout?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Самое главное это то, что $timeout обновляет скоуп (всякие данные на страничке изменятся), а простой setTimeout ничего не обновит в скоупе (данные на страничке как были так и будут старые).

    Еще самое главное — $timeout ни в коем случае не является заменой setTimeout!!!

    Если у вас функционал, который работает с данными скоупа и биндит переменные, то используйте $timeout, если же вам просто нужно что-то исполнять по таймауту (например, раз в секунду что-то делать, потом, через секунду, опять, и так далее, но не связанное с обновлением данных скоупа), то используйте setTimeout. Тобишь, $timeout запускает $digest-цикл и перерисовывает страничку — вот и представьте, если вы каждую секунду будете перерисовывать страничку.
    Ответ написан
    Комментировать
  • AngularJS, как при пагинации возвращаться наверх странницы?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    В самом главном контроллере слушайте изменения УРЛ страницы и крутите наверх:
    $rootScope.$on('$routeChangeSuccess', function(e, current, previous) {
        window.scrollTo(0, 0);
    });


    UPD:
    Если вы хотите сделать пагинацию на сайте вида mysite.ru/1, то в роутах у вас должно быть примерно следующее:
    $routeProvider
         .when('/:pageNumber?', {
              templateUrl: 'partials/home.html',
              controller: 'HomeCtrl'
         })


    В контроллере присоединяйте $routeParams, чтобы считывать переменные из роута, а так же присоединяйте paginationService, у него есть метод setCurrentPage, который задает текущую страницу:
    watchesStore.controller('WatchesStoreController', function($routeParams, paginationService) {
        var pageNumber = $routeParams.pageNumber || 1;
            pageNumber = parseInt(page, 10);
    
        var paginationId = 'watchesStore'; // setCurrentPage требует instanceId — айдишку экземпляра пагинатора, чтобы знать, какой блок, собственно, пагинировать
    
        paginationService.setCurrentPage(paginationId, pageNumber);
    });


    А в HTML-коде у вас нужно еще айдишку экземпляра пагинации (мы его назвали watchesStore) вставить в директиву:
    <dir-pagination-controls boundary-links="true" on-page-change="pageChangeHandler(newPageNumber)" template-url="dirPagination.tpl.html" pagination-id="watchesStore"></dir-pagination-controls>


    UPD2:
    А, только что заметил, что у вас уже есть роут для айдишки часов:
    $routeProvider
        .when('/:watchId', {
            templateUrl: 'partials/watch-detail.html',
            controller: 'WatchDetailCtrl'
        })


    Значит, для пагинации используйте не mysite.ru/1, а обычные GET-параметры mysite.ru/?page=1. В результате в контроллере страничку будете получать так:
    watchesStore.controller('WatchesStoreController', function($location, paginationService) {
        var params = $location.search();
    
        var pageNumber = params.page || 1;
            pageNumber = parseInt(page, 10);
    
        ...
    });
    Ответ написан
    3 комментария
  • Как лучше организовать динамическое обновление блоков HTML на JS?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Только лишь для одного виджета корзины Ангулар подключать конечно же не стоит :)

    На Ангуларе это делается следующим образом — есть директива корзины (виджет) и есть сервис корзины. Добавление товаров в корзину идет через сервис, а директива слушает изменения сервиса и выводит у себя обновленную инфу.

    Вот Директива:
    angular.module('app').directive('shoppingCartWidget', function(shoppingCartService) {
        return {
            restrict: 'E',
            replace: true,
            scope: {},
            templateUrl: 'shopping-cart.html',
            link: function(scope, element, attributes) {
                scope.items = [];
    
                // слушаем изменения в корзине
                scope.$watch(shoppingCartService.getItems, function(items) {
                    scope.items = items;
                });
            }
        }
    });


    Вот сервис:
    angular.module('app').directive('shoppingCartService', function(_) {
        var items = [];
    
        function add(itemData) {
            items.push(itemData);
        }
    
        function remove(itemID) {
            items = _.reject(items, {id: itemID});
        }
    
        function clear() {
            items = [];
        }
    
        function getItems() {
            return items;
        }
    
        return {
            add: add,
            remove: remove,
            clear: clear,
            getItems: getItems
        }
    });


    Вот контроллер:
    angular.module('app').controller('myController', function(shoppingCartService) {
    
        // ну, тут будет не массив, а $resource, например
    
        $scope.items = [
            {
                id: 1,
                name: 'Клавиатура',
                price: 150
            },
            {
                id: 2,
                name: 'Кофе',
                price: 50
            }
        ];
    
        $scope.addToCart = addToCart;
    
        function addToCart(itemData) {
            shoppingCartService.add(itemData);
        }
    
    });


    Вот вьюха списка товаров:
    <ul>
        <li ng-repeat="item in items">
            <span>{{item.name}}</span>
            <button ng-click="addToCart(item)">Добавить в корзину</button>
        </li>
    </ul>
    Ответ написан
    5 комментариев
  • Как в AngularJS проскролить окно до первого невалидного инпута?

    mudrick
    @mudrick
    Máximo progreso hemos alcanzado en minimo seso.
    Скроллить браузер не нужно — достаточно просто поставить .focus() на элемент, браузер сам прокрутит куда надо. (Извиняюсь, не заметил, что вопрос был задан год назад :)
    Ответ написан
    Комментировать