user1141796
user1141796

Reputation: 334

Angular controller function outside current controller

I have 4 controllers in my Angular 1.x app:

  1. houseController
  2. apartmentController
  3. addressController
  4. contactInfoController

With addressController & contactInfoController I update the address and contact info of a house or an apartment.

I work in the following way:

<div ng-controller="houseController" ng-init="getHouseInformation()>
    {{house.contact_info.email}}
    {{house.contact_info.mobile_phone_number}}

    <a ng-controller="contactInfoController" ng-click="showContactInfoEdit(house.contact_info.id)">Edit</a>
</div>

When the update of the contact information is successfull within the contactInfoController, I want to update the house information getHouseInformation() in the houseController (read: make a new call to the API to get the updated information).

Since I have more than one (and in the future even more) house/apartment/... controllers, I need to have a solid way on how to 'refresh' the scope of these apartments, houses, ... on the fly.

What would be the best solution in my case?

Edit:

My scopes look like this:

// in houseController

$scope.house = {
    id : 1,
    title : "House title",
    contact_info : {
        email: '',
        mobile_phone_number : ''
    }
}

// in apartmentController

$scope.apartment = {
    id : 1,
    title : "Apartment title",
    contact_info : {
        email: '',
        mobile_phone_number : ''
    }
}

// in contactInfoController

$scope.contact_info : {
    email: '',
    mobile_phone_number : ''
}

So when updating the contact information scope, I'm not directly changing the house scope... Hope this helps.

Upvotes: 0

Views: 120

Answers (3)

AquaVitae
AquaVitae

Reputation: 177

I disagree with the other advice you got here - directives help you intelligently manipulate the DOM with your data but not necessarily share it between scopes, which is what you're asking about. As I wrote to you on Slack, what you seem to be looking for is a Service which will contain all your data (either declared in it or linked to an external file or API), and then injected into every controller that needs access to that data. That's one of the main uses for services!

For posterity, here's what I wrote to you on Slack: "...You’re currently creating unrelated objects that don’t communicate - why should they? They’re in different scopes. You’re actually not getting any use out of Angular and could use vanilla Javascript for that:)

The idea is to use persistent data that is ​shared​ across your web app. $scope.anything will never communicate outside its scope unless you ​bind​ it to something outside the scope, like a service. Whether the service draws data from an external API or really just an object model that lies ​outside​ of Angular, (on your server/file structure, for example), or even defined within the service itself doesn’t matter (although the latter is far from a best practice) - but you need something persistent outside of the local scopes that's shared between your controllers/views.

Then there are a few ways to connect the dots. A very common (and probably the best) design pattern is to create a ​service​ (NOT directive! I don’t know why they gave you that advice) that encapsulates that data. So, for example,

myApp.service(‘dataModel', function(){

$scope.houses = {}; //an object containing ALL the houses, each one containing ALL the apartments, each apt.containing ALL the contact info, etc. etc.

});

Then in your controllers you pass the dataModel service, and then declare and link the local scope 'reference' of the same object to it, for example:

myApp.controller(‘buildingsView’, [dataModel, function(dataModel){

//and link to that service’s object locally:
$scope.houses = dataModel.houses;
}]);

Then, once you affect that model in one view/controller, the data in the other views/controllers will magically change too!

And ​that​ is the angular way:)

Hope this makes sense!

(To clarify, there are two issues here: getting your data INTO angular and then SHARING that same object by injecting the same service to your various controllers. That’s sort of the exact idea of services - they’re singletons, which means only one copy of them exists at any time and if they’re referred to more than once, it’ll always be to the same object, which is why manipulating it in one place will change it in another.)"

Upvotes: 1

Simon Sch&#252;pbach
Simon Sch&#252;pbach

Reputation: 2683

I suggest to use directive, then it's easier to exchange data. And that is the reason why directive exists. I try to explain how to build your use case with directives. Assume that you have one controller (houseController) and for every sub requirements you make a directive. One for the contact, one for the appartment and one for the address. Then you define your whole object inside houseController. You pass all necessary data as a parameter to the directive and you can access them from the houseController or from inside the directive, because of the two way data binding. In this way you don't have to exchange something or to call update functions. You adjuste just the object.

your html

<div ng-controller="houseController">
    <contact data="house.contact"></contact>
    <apartment data="house.apartment"></apartment>
    ...
</div>

house controller

$scope.house = {
  apartment:{
     floor: 1, 
     number:34,
     ...
  },
  contact:{
    id:2, 
    email:"[email protected]", 
    mobile_phone_number:"123456789",
    ...
  },
  ...
}

contact directive

.directive('contact', function() {
  return {
    restrict: 'E',
    scope: {
      data: '='
    },
    link: function(scope, element, attrs) {
       scope.showContactInfoEdit = function(id){
          // do your stuff here
          scope.data.name = "Peter";
       }
    },
    templateUrl: 'contact.html'
  };
});

contact.html

 {{data.email}}
 {{data.mobile_phone_number}}
 <a ng-click="showContactInfoEdit(data.id)">Edit</a>

I made a plunkr: http://plnkr.co/edit/8tRMtgztaXRC3EKyQhcH?p=preview

Upvotes: 0

Andrew Donovan
Andrew Donovan

Reputation: 552

Put your data within a $scope variable, and make your controllers watch this varaible from scope. When the event is triggered, you can then do what you want.

$scope.houses = [];
$scope.$watch('houses', function(newValue, oldValue) {
// This is triggered when $scope.houses changes directly
// Add true as param to this function if you want to watch properties nested within the houses object
});

If houses is within a controller, use the following:

(in controller)

var self = this;
self.houses = [];
// This tells angular to watch the controller property houses instead of a scope variable
$scope.$watch(function(){return self.houses}, function(newValue, oldValue) {
// This is triggered when $scope.houses changes directly
// Add true as param to this function if you want to watch properties nested within the houses object
});

Upvotes: 0

Related Questions