File Manager cz. V - Edycja i usunięcie folderu AngularJS

Kategoria: AngularJS

Autor: admin@ignaszewski.pl | Opublikowany: 29 czerwca 2014

Kolejna etap tworzenia naszego filemanagera to przygotowanie interfejsu umożliwiającego zmianę nazwy utworzonych folderów oraz usunięcie folderu. Jeśli chodzi o tą drugą funkcjonalność to dla uproszczenia mechanizmu przyjmijmy sytuację, że folder można usunąć tylko wtedy, gdy jest on pusty (nie zawiera podkatalogów ani plików).

Aby móc skorzystać z nowych funkcjonalności potrzebujemy odpowiedniego interfejsu po stronie użytkownika. Załóżmy, że będzie to wysuwające się z góry menu, w postaci dwóch ikonek, w momencie najechania na ikonę folderu.

// main.jade
...
.thumb.thumb-folder.img-thumbnail(ng-repeat="dir in dirs | filter:{'name': search } | orderBy:'name'", ng-click="goToFolder(dir)")
    i.thumb-image.fa.fa-folder-o
    .thumb-name(data-ng-bind="dir.name")
    .menu.folder-menu
        i.fa.fa-edit(ng-click="editFolder(dir, $event)")
        i.fa.fa-trash-o(ng-click="removeFolder(dir, $event)")

do tego odrobina styli:

// main.less
.main-panel {
	.thumb {
		...
		.menu {
			position: absolute;
			left: 0;
			top: -28px;
			width: 100%;
			-webkit-transition: all linear 200ms;
			-moz-transition: all linear 200ms;
			-ms-transition: all linear 200ms;
			-o-transition: all linear 200ms;
			transition: all linear 200ms;

			i {
				display: inline-block;
				width: 50%;
				font-size: 20px;
				padding: 4px 0;
				background-color: rgba(204,204,204,0.4);

				&:hover {
					color: @hoverColor;
					background-color: rgba(204,204,204,0.7);
				}
			}
		}
	}
}

Teraz możemy przejść do stworzenia odpowiednich funkcjonalności.

Edycja nazwy

Zmianę nazwy rozwiążemy poprzez wyświetlenie odpowiedniego formularza powyżej okna listy folderów umożliwiającego wprowadzenie nowej nazwy folderu. Całość zostanie oparta na osobnym routingu, tak jak dodawanie nowego folderu. Zatem do dzieła. Dodajmy routing main.edit:

// app.js
...
.state('main.edit', {
    url: '/edit/:changeDirId',
    templateUrl: '/templates/dir_edit.html',
    controller: 'EditDirCtrl'
})

Już kilka tych linijek mówi nam jak będzie wyglądała cała naszą funkcjonalność. Będziemy potrzebowali szablonu dir_edit.jade zawierającego tytuł, pole do wprowadzenia nowej nazwy, oraz przyciski Zapisz i Anuluj. Przy czym przycisk Anuluj będzie powodował zamknięcie okna zmian i powrót do poprzedniego widoku.

<pre// dir_edit.jade .panel.panel-default.main-panel .panel-body h2. Zmień nazwę folderu "{{ orgName }}" .alert.alert-danger(ng-show="folder_add.$invalid && folder_add.$dirty") p. Nazwa folderu nie może być pusta form.form.form-horizontal(name="folder_add", novalidate, style="margin: 10px;") .form-group input.form-control(type="text", name="folder_name", ng-model="folderName", placeholder="Nazwa folderu", required) .btn-group.pull-right button.btn.btn-success(ng-disabled="folder_add.$invalid || folderName == orgName", ng-click="saveFolder()") i.fa.fa-check. Zapisz button.btn.btn-danger(ng-click="goBack()") i.fa.fa-times. Anuluj

Do tak przygotowanego szablonu będzie nam potrzebny kontroler EditDirCtrl, który pozwoli nam w prosty sposób kontrolować naszą zmianę nazwy.

// EditDirCtrl.js
'use strict';
angular.module('filemanager')
    .controller('EditDirCtrl', ['$scope', '$state', '$timeout', 'DirStructure', function($scope, $state, $timeout, DirStructure){

        $scope.changedDir = DirStructure.getSubDirById($state.params.changeDirId);

        $scope.folderName = $scope.changedDir.name;

        $scope.orgName = $scope.folderName;

        $timeout(function(){
            angular.element('input[name="folder_name"]').focus();
        }, 200);


        $scope.goBack = function(){
            $state.go('main', {dirId: $state.params.dirId});
        }

        $scope.saveFolder = function(){
            if($scope.folderName !== '')
            {
                DirStructure.saveFolder($scope.changedDir, $scope.folderName, $scope.goBack);
            }
        }
    }])
;

Poszczególnymi elementami naszego kontrolera są:

  • changedDir - zmieniany folder

  • folderName - nowa nazwa folderu

  • orgName - bieżąca nazwa folderu

Dodatkowo mamy dwie funkcje:

  • goBack - podpięta do przycisku Anuluj powoduje powrót do poprzedniego stanu bez wprowadzania jakichkolwiek zmian

  • saveFolder - podpięta do przycisku Zapisz powoduje zmianę nazwy folderu i powrót do poprzedniego widoku

Wydaje mi się, że wszystko jest na tyle proste, iż nie wymaga dodatkowego komentarza. Jedyna rzecz jaka tego wymaga to wykorzystanie funkcji saveFolder z obiektu DirStructure. Wygląda ona nastepująco:

// models.js
…

        this.removeFolder = function(dirObj, callbackSuccess, callbackError){
            var that = this;
            $http.post('/api/directory/remove', {dir_id: dirObj.id})
                .success(function(data){
                    if(!data.error)
                    {
                        that.currentDir.dirs = _.remove(that.currentDir.dirs, {id: parseInt(dirObj.id)});
                        if(callbackSuccess)
                        {
                            callbackSuccess();
                        }
                    }
                    else
                    {
                        if(callbackError)
                        {
                            callbackError(data);
                        }
                    }
                })
                .error(function(data){
                    if(callbackError)
                    {
                        callbackError(data);
                    }
                })
            ;
        }

Jak widać funkcja wywołuje żądanie POST do serwera przekazując identyfikator folderu oraz jego nową nazwę. Jeśli wszystko się powiedzie i nie zostanie zwrócony błąd to wykonywana jest funkcja callbackSuccess na danych które zwrócił serwer, w przeciwnym wypadku wykonywana jest funkcja callbackError. Dane jakie skrypt spodziewa się otrzymać ze strony serwera to w przypadku:

  • sukcesu - {“success”: true}

  • błędu - {“error”: true}

 

Usuwanie folderu

Funkcjonalność usuwania folderów tak jak pisałem wcześniej będzie ograniczała się jedynie do przypadku w którym usuwany folder jest pusty. Będzie oparta także na osobnym routingu podobnie jak edycja czy dodawanie folderu. Jak to będzie wyglądało? Chciałbym aby chęć usunięcia folderu została poprzedzona stosownym komunikatem, który użytkownik potwierdzi lub nie. Zacznijmy zatem od początku, czyli routingu - nie różni się on zbytnio od tego dla edycji.

// app.js
…
.state('main.remove', {
            url: '/remove/:removeDirId',
            templateUrl: '/templates/dir_remove.html',
            controller: 'RemoveDirCtrl'
        })

Tak jak routing, tak i szablon, kontroler, czy odpowiednia funkcja modelu są podobne do tych z funkcjonalności zmiany nazwy, więc wydaje mi się, że nikt ni będzie miał problemów ze zrozumieniem tego fragmentu kodu.

Oczywiście wszystkie stworzone funkcje zostały pokryte odpowiednimi testami, tak by sprawdzić ich podstawowe działanie.