0

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.

Dave Long
  • 9,569
  • 14
  • 59
  • 89
  • possible duplicate of [What's the correct way to communicate between controllers in AngularJS?](http://stackoverflow.com/questions/11252780/whats-the-correct-way-to-communicate-between-controllers-in-angularjs) – domokun Jul 07 '14 at 13:55
  • That's where I thought I'd find my answer, but I think the root of my problem is really around `Array#concat` and binding to it. – Dave Long Jul 07 '14 at 13:58
  • Did you tried instead of `InvociesSrvc.clientInvoices.concat data.client_invoices` using an actual method that you could invoke with `InvociesSrvc.addClientInvoice(data.client_invoices)` ? – domokun Jul 07 '14 at 14:03
  • Also, you have a typo in your code... `InvociesSrvc.clientInvoices.concat data.client_invoices` while the factory is named `InvoicesSrvc` – domokun Jul 07 '14 at 14:04
  • @domokun The code is not directly copied to protect some of the data in the code. I haven't tried a `#addClientInvoice` method yet. I'm still having trouble getting the binding to work between clientInvoices and the table when I use `Array#concat` in my HTTP response. – Dave Long Jul 07 '14 at 14:08
  • @domokun Using an `#addClientInvoice` method did work once I implemented it correctly. Would you like to create an answer so I can give you the points for it? – Dave Long Jul 07 '14 at 14:31

1 Answers1

1

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.

domokun
  • 3,013
  • 3
  • 29
  • 55