Dave Long
Dave Long

Reputation: 9759

Sending data between controllers in Angular

I have a section of my app for "Client Invoices" which includes 2 components [for now]: Invoice List and New Invoice Modal Form.

The view looks like this:

%h2 Client Invoices

%div(ng-controller="ClientInvoicesCtrl as clientInvoicesCtrl")

  %div(ng-controller="NewInvoiceModalCtrl as newInvoiceModal")
    %a.button(href="#' ng-click="newInvoiceModal.open()") + New Invoice

  %table
    %thead
      %tr
        %th Client
        %th Invoice #
        ...
    %tbody
      %tr(ng-repeat="invoice in clientInvoices")
        %td {{ invoice.client.name}} ({{invoice.client.id}})
        %td {{ invoice.id }}
        ...

And my logic is this:

app.controller 'ClientInvoicesCtrl', ['$http', '$scope', ($http, $scope) ->
  $scope.clientInvoices = []
  $http
    .get '/clients/invoices.json'
    .success (data) ->
      $scope.clientInvoices = data.client_invoices
]

app.controller 'NewInvoiceModalCtrl', ['$modal', ($modal) ->
  @open = ->
    modalInstance = $modal.open {
      templateUrl: '/clients/invoices/new'
      controller: 'NewInvoiceModalInstanceCtrl'
      windowClass: 'small'
    }
]

app.controller 'NewInvoiceModalInstanceCtrl', ['$scope', '$modalInstance', ($scope, $modalInstance) ->
  $scope.clientInvoice = {
    id: ''
    client_id: ''
    start_on: new Date()
    amount: ''
  }

  $scope.save = ->
    # need to push $scope.clientInvoice into ClientInvoicesCtrl.clientInvoices
    $modalInstance.close()
]

So there's a controller that wraps the entire section and then a modal controller within that.

What I want to do is feed from the NewInvoiceModalInstanceCtrl into the ClientInvoicesCtrl to pass the newly created invoice in the modal to the invoices list. I attempted to change towards a service to communicate between the 2 controllers with the following:

app.factory 'InvoicesSrvc', ->
  return { clientInvoices: [] }

app.controller 'ClientInvoicesCtrl', ['$http', '$scope', 'InvoicesSrvc', ($http, $scope, InvoicesSrvc) ->
  $scope.clientInvoices = InvoicesSrvc.clientInvoices
  $http
    .get '/clients/invoices.json'
    .success (data) ->
      InvociesSrvc.clientInvoices.concat data.client_invoices
]

...

app.controller 'NewInvoiceModalInstanceCtrl', ['$scope', '$modalInstance', 'InvoicesSrvc', ($scope, $modalInstance, InvoicesSrvc) ->
  ...

  $scope.save = ->
    # need to push $scope.clientInvoice into ClientInvoicesCtrl.clientInvoices
    InvoicesSrvc.clientInvoices.push $scope.clientInvoice

    # ... post request to submit to server ...
    $modalInstance.close()
]

This doesn't seem to work though. There seems to be a problem when using Array#concat with bindings.

I've created a GitHub Gist for the 2 versions (see revisions) of my code.

Upvotes: 0

Views: 78

Answers (1)

domokun
domokun

Reputation: 3003

Instead of using an empty array that gets referenced from the outside like this:

app.factory 'InvoicesSrvc', ->
  return { clientInvoices: [] }

...

//later in the code
InvociesSrvc.clientInvoices.concat data.client_invoices

You can write a factory which stores the same array, but exposes some methods to manipulate the data. A simple structure like this one can do the trick:

app.factory('InvoiceSrvc', function () {

  // your private data (and eventually functions) goes here
  var clientInvoices = []

  // your public API gets returned here
  return {

    addClientInvoice: function (invoice) {
      clientInvoices.push(invoice)
    }

  }      
})

Then you can, of course, add every method you may need to manipulate the array.

Upvotes: 1

Related Questions