Статьи

10 полезных рекомендаций и фильтров для AngularJS

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

Проверка адреса электронной почты 

validateEmail: function (email) {
   var rx = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
   return rx.test(email);
}

Для проверки адреса электронной почты мы используем простое регулярное выражение. Обратите внимание, что он используется только для проверки того, что пользователь не ввел очевидную чепуху. Если вы будете следовать 
стандарту RFC , то можете столкнуться с некоторыми трудностями. Это связано с различными факторами: постоянное обновление списка доменных зон, использование интернационализированных доменов (IDN), использование конфиденциальных адресов и многое другое. Таким образом, наша проверка проверяет только общую структуру адресов (наличие ‘@’ и точки), в противном случае она зависит от адекватности пользователя. Если вы действительно хотите проверить адреса электронной почты, лучше использовать подтверждение по электронной почте, чем придумывать громоздкие регулярные выражения. 

Нахождение элемента в массиве по значению

getByProperty: function (array, val, type) {
    var length = array.length;
    for (var i = 0; i < length; i++) {
        if (array[i][type] === val) {
            return a[i];
        }
    }
    return null;
}

Задача поиска в массиве по указанному в поле значению встречается довольно часто. Например, его можно использовать для поиска элемента с определенным идентификатором. Простейшая функция getByProperty исключает частое использование циклов в коде.

Пример использования:

user = getByProperty(usersArray, 1, 'id');

Генерация уникального идентификатора

При разработке одностраничных приложений (SPA, одностраничных приложений) иногда требуется создавать уникальные идентификаторы непосредственно на стороне клиента (front-end). Чтобы эти идентификаторы правильно работали с сервером (серверной частью), вы должны создать их в обычном  формате UUID  . Вот небольшая функция, которая никогда не подводила:

generateUUID: function () {
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
    s[8] = s[13] = s[18] = s[23] = "-";
    return s.join("");
}

Обработка нажатием Enter при вводе

Чтобы улучшить восприятие вашего продукта, стоит подумать даже о мелких деталях. Например, вы должны позволить пользователю по-прежнему работать с его обычными горячими клавишами. После заполнения некоторых данных в текстовом поле я хочу подтвердить действие, нажав Enter, вместо того, чтобы отрывать руки от клавиатуры и перетаскивать курсор на кнопку.

app.directive('ngEnter', [function () {
    return function (scope, element, attrs) {
        element.bind('keydown keypress', function (event) {
            if (event.which === 13) {
                scope.$apply(function (){
                    scope.$eval(attrs.ngEnter);
                });

                event.preventDefault();
            }
        });
    };
}]);

Вот как использовать эту директиву:

<input type="text" ng-enter="action()"/>
<button ng-click="action()">Action!</button>

Представление байтов в удобном для человека формате

Поскольку  BitCalm  обычно использует измерение размеров файлов, нам нужен инструмент для преобразования единиц измерения в удобный формат на лету. Для этого был написан следующий фильтр для Angular: 

app.filter('bytes', function() {
    return function(bytes) {
        if (isNaN(parseFloat(bytes)) || !isFinite(bytes) || bytes == 0) return '0';

        var units = {1: 'KB', 2: 'MB', 3: 'GB', 4: 'TB'},
            measure, floor, precision;

        if (bytes > 1099511627775) {
            measure = 4;
        } else if (bytes > 1048575999 && bytes <= 1099511627775) {
            measure = 3;
        } else if (bytes > 1024000 && bytes <= 1048575999) {
            measure = 2;
        } else if (bytes <= 1024000) {
            measure = 1;
        }

        floor = Math.floor(bytes / Math.pow(1024, measure)).toString().length;
        if (floor > 3) {
            precision = 0
        } else {
            precision = 3 - floor;
        }
        return (bytes / Math.pow(1024, measure)).toFixed(precision) + units[measure];
    }
});

Вот как это работает:

<span>{{ 234242345 | bytes }}</span> <!-- '223MB' -->
<span>{{ 56734654 | bytes }}</span>  <!-- '54.1MB' -->
<span>{{ 1024 | bytes }}</span>      <!-- '1.00KB' -->

Создание вложенной прокрутки

Ситуация, когда на странице с полосой прокрутки есть подэлемент, который вы также можете прокручивать, вызывает большие неудобства.

вложенный-scrolling.JPG

Когда курсор находится над областью 2, прокручиваются обе полосы прокрутки, что делает невозможным комфортный просмотр содержимого в этой области. Чтобы решить эту проблему, мы используем простую директиву:

app.directive('nestedScroll', [function () {
    return function (scope, element) {
        element.on('mousewheel DOMMouseScroll', function (e) {
            var e0 = e.originalEvent || e,
                delta = e0.wheelDelta || -e0.detail;

            this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
            e.preventDefault();
        });
    }
}]);

Когда вы наводите курсор мыши на нужный элемент, стандартное действие блокируется, и с помощью функции scrollTop применяется простая операция.

Воспроизведение звука при определенных событиях

Если ваше приложение требует создания звука при определенных событиях, это можно сделать с помощью следующих директив:

app.directive('soundNotification', [function () {
    return function (scope, element, attrs) {
        scope.$on('playSound', function () {
            element.attr('src', '');
            element.attr('src', attrs.msrc);
            element[0].play();
        });
    }
}]);

Теперь из всех мест приложения вы можете отправлять события playSound с помощью $ emit и $ broadcast. Элемент должен иметь атрибут «msrc» с указанием пути к файлу. В противном случае путь может быть отправлен к событию в качестве аргумента.

Определение активности браузера вкладок

Иногда вам нужно выполнить какое-либо действие, когда пользователь переключается со вкладки в вашем приложении (примеры действий — включение звуковых оповещений, включение уведомлений через браузер и т. Д.). Для этого можно использовать следующую функцию:

detectTabActivity: function (focusInCallback, focusOutCallback) {
    var notIE = (document.documentMode === undefined);

    if (notIE && !window.chrome) {
        $(window).on("focusin", focusInCallback).on("focusout", focusOutCallback);
    } else {
        if (window.addEventListener) {
            window.addEventListener("focus", focusInCallback, false);
            window.addEventListener("blur", focusOutCallback, false);
        } else {
            window.attachEvent("focus", focusInCallback);
            window.attachEvent("blur", focusOutCallback);
        }
    }
});

Две функции обратного вызова, предназначенные для ввода, могут выполнять любые действия с событиями «фокус» или «размытие».

Я надеюсь, что этот метод будет таким же полезным для вашей работы в AngularJS, как и  для нашей  .