3

I'm working in a small Angularjs 1.5 project and I'm quite new.

I have to create an object or edit an existing object and the template is the same, the only difference in the logic is the call to an http service for data retrieve in case of update. I use ngRoute. How can I do to use the same component for both operations ?

EDIT

JS COMPONENT CODE

angular.
module('editProject').
    component('editProject', {
        templateUrl: 'app/edit-project/edit-project.template.html',
        controller:['$http','$routeParams', function EditProjectController($http,$routeParams) {
            var self=this;
            $http.get('rest/projects/' + $routeParams.id ).then(function(response) {
              console.log(JSON.stringify(response.data));
              self.project = response.data;
            });


        }
  ]
  });

ROUTE CONFIG

angular.
  module('myApp').
   config(['$locationProvider', '$routeProvider',
   function config($locationProvider, $routeProvider) {
      $locationProvider.hashPrefix('!');

      $routeProvider.
    when('/projects', {
      template: '<project-list></project-list>'
    }).
    when('/projects/:id', {
      template: '<project-detail></project-detail>'
    }).
    when('/projects/edit/:id', {
        template: '<edit-project></edit-project>'
      }).
    when('/projects/new', {
        template: '<edit-project></edit-project>'
    }).  
    otherwise('/projects');
}
 ]);
Massimo Petrus
  • 1,881
  • 2
  • 13
  • 26

1 Answers1

2

1. Quick fix

Simple solution would be using a conditional checking if the $routeParams.id param is defined, if so, then it need a request to feed the project informations, otherwise not.

if($routeParams.id){
    $http.get('rest/projects/' + $routeParams.id ).then(function(response) {
        console.log(JSON.stringify(response.data));
        self.project = response.data;
    });
}

2. Component Router

Even though the previous solution looks simple and functional, it might not be the best. A propper solution is to use a separate component for each route, but you can reuse the form part of it. Also, assuming that you are building a completelly component-based app you should use ngComponentRoute instead of ngRoute.

.component('app', {
  template: '<ng-outlet></ng-outlet>',
  $routeConfig: [
    {path: '/projects', name: 'Projects', component: 'projectList', useAsDefault: true},
    {path: '/projects/:id', name: 'Project Detail', component: 'projectDetail' },
    {path: '/projects/edit/:id', name: 'Edit Project', component: 'editProject' },
    {path: '/projects/new', name: 'New Project', component: 'newProject' }
  ]
});

Then you can create a project editor component and reuse it on both edit and new project page by just adding <project-editor-form project="{}" on-save="$ctrl.mySave()"></project-editor-form>. For example:

.component('projectEditorForm', {
    template:
      'Project Name: <input type="text" ng-model="$ctrl.project.name">' +
      '<button ng-click="$ctrl.onSaveProject($ctrl.project)">Save</button>',
    bindings: {
        project: '<',
        onSave: '&'
    },
    controller: function () {
        var $ctrl = this;
        $ctrl.onSaveProject = function (project) {
            // general save logic goes here
            // if you want to reuse this too
            // then emit the on save for onSave binding
            $ctrl.onSave($ctrl.project);
        }
    },
  })

.component('editProject', {
    template:
      '<project-editor-form project="$ctrl.project" on-save="$ctrl.mySave()">' + 
      '</project-editor-form>',
    bindings: {
        project: '<',
        onSave: '&'
    },
    controller: function ($http) {
        var $ctrl = this;

        // consider using a Service to do such task
        // instead of request directly from the controller
        $http.get('rest/projects/' + $routeParams.id).then(function(response) {
            $ctrl.project = response.data;
        });

        $ctrl.mySave = function (project) {
            // save logic here
        }
    },
  })

3. ngRoute with resolve

Another approach that doesn't deppend on ngComponentRoute, is to use the route resolve property, it's very usefull when using component as route template. You add a resolve property to your route, that would be the project, and bind to your form component.

$routeProvider
  .when('/projects/edit/:id', {
    template: '<project-editor-form project="$resolve.project"></project-editor-form>',
    resolve: {
      project: function ($route, $q) {
        var id = $route.current.params.id;
        // again, consider using a service instead
        return $http.get('rest/projects/' + id).then(function (response) {
          return response.data;
        });
      }
    }
  })
  .when('/projects/new', {
    template: '<project-editor-form project="$resolve.project"></project-editor-form>',
    resolve: {
      project: {
        id: 0,
        name: ''
      }
    }
  })
lenilsondc
  • 9,590
  • 2
  • 25
  • 40
  • very nice proposal! Unfortunately ngComponentRoute has been deprecated but i think isnonot an issue. How if i want to reuse the save logic too? – Massimo Petrus Nov 03 '16 at 18:09
  • Yes it has been deprecated, and yes this is not an issue (you can use ngRoute, unfortunately it's now component routing but it will work just fine). If you want to reuse the save logic you can move the save logic within the projectEditorForm` and build the save logic, also consider moving the save logic to a service and just use the service to call the login from the component.. – lenilsondc Nov 03 '16 at 18:21
  • @Massimo I've updated my answer with a new example, It's a different approach, but it can be usefull – lenilsondc Nov 03 '16 at 19:24
  • Please take a look to my new question http://stackoverflow.com/questions/40421939/angularjs-1-5-component-based-architecture-bindings-and-good-practices – Massimo Petrus Nov 04 '16 at 11:49