Dark Cyber
Dark Cyber

Reputation: 2231

AngularJS How to access local scope from outside function?

I have this code in my service

orderSewaService.vehicleDetail = function (license_plate) {

        //var defer = $q.defer();

        var config = {
            headers: {
                'X-Parse-Application-Id': parseAppId
            },
            params: {
                where: {
                    vehicle_license_plate: license_plate,
                    vehicle_status: 'available'
                },
                limit: 1,
                include: 'car_id.car_class_id,pool_id.city_id,partner_id.user_id'   
            }

        }

        return $http.get('http://128.199.249.233:1337/parse/classes/vehicle', config).then(function (response) {
            var detail = {
                license_plate: response.data.results[0].vehicle_license_plate,
                photo: response.data.results[0].vehicle_photo,
                partner_name: response.data.results[0].partner_id.user_id.full_name,
                year: response.data.results[0].vehicle_year,
                class: response.data.results[0].car_id.car_class_id.name,
                pool_address: response.data.results[0].pool_id.pool_address,
                city: response.data.results[0].pool_id.city_id.city_name,
                zone_id: response.data.results[0].zone_id.objectId,
                car_class_id: response.data.results[0].car_id.car_class_id.objectId         
            };

            return detail;

            //defer.resolve(detail);
        }, function (error) {
            //defer.reject(error);
            return error;
        });             

        //return defer.promise;     

    };

in my controller

$scope.vehicle = {};
 orderSewaService.vehicleDetail($routeParams.license_plate).then(function(response){
                $scope.vehicle = response;//rendered in view
                console.log($scope.vehicle); //log object success
            }, function (error) {
                console.log(error);
            });

            console.log($scope.vehicle); //doesn't work //empty object
            //My goal is I will call other service function like this
            orderSewaService.infoTarif($scope.vehicle.zone_id, $scope.vehicle.car_class_id).then(...);

Already read this access scope data from outside function but looks like to complex or not suit for my simple goal.

How I can access $scope.vehicle outside function or how to achieve my goal ?

And I don't think $rootScope is good solution in this case.

Upvotes: 0

Views: 109

Answers (3)

Taku
Taku

Reputation: 5918

I think there are two matter of concerns in this question.

Firstly - sync & async methods

Since orderSewaService.vehicleDetail is asynchronous, $scope.vehicle would be null.

If you are not sure what that means, compare the two:

var foo = null;

foo = ['a','b'];

console.log(foo); // ['a','b']

versus

var foo = null;

setTimeout(function(){
    foo = ['a','b'];
    console.log(foo); // array
}, 500); // or any value including zero

console.log(foo); // null

Conclusively, your code should look like this:

$scope.vehicle = {};
orderSewaService
    .vehicleDetail($routeParams.license_plate)
    .then(function(response){
        $scope.vehicle = response;//rendered in view
        console.log($scope.vehicle); //log object success

        //My goal is I will call other service function like this
        orderSewaService.infoTarif($scope.vehicle.zone_id, $scope.vehicle.car_class_id).then(...);

    }, function (error) {
        console.log(error);
    });

There are a ton of articles and docs that describe this, if you are further interested.

Secondly - load contents before reaching controller

Now, from how you described the problem, it seems like you also want to load the contents of orderSewaService.vehicleDetail based on a URL parameter before it reaches the controller. Otherwise, you will have to call orderSewaService.vehicleDetail and orderSewaService.infoTarif in every controller.

A much cleaner and more common approach is to use ui-router's $stateProvider. Tutorials here

If you run a few examples from their docs, you can inject dependencies into your controller like this:

app.route.js

$stateProvider
.state('vehicles', {
    url: '/vehicles',
    resolve: { 
        vehicles: ['VehiclesService', function(VehiclesService){
            return VehiclesService.getAll();
        }]
    },
    controller: 'VehiclesListCtrl',
    templateUrl: 'vehicles.html'
})
.state('vehicles.detail', {
    url: '/vehicles/:vehicleId',
    resolve: { 
        info: ['VehiclesService', '$stateParams', function(VehiclesService, $stateParams){
            return VehiclesService.get($stateParams.vehicleId)
                 .then(function(vehicle){
                     return orderSewaService.infoTarif(vehicle.zone_id, vehicle.car_class_id)
                     .then(function(tarif){
                         return {
                             vehicle: vehicle,
                             tarif: tarif
                         };
                     });
                 });
        }]
    },
    controller: 'VehicleDetailCtrl',
    templateUrl: 'vehicle.detail.html'
});

vehicle.detail.controller.js

.controller('VehicleDetailCtrl', VehicleDetailCtrl);

    VehicleDetailCtrl.$inject = [
        '$scope',
        'info'
    ];

    function VehicleDetailCtrl(
        $scope,
        info
    ) {
        console.log('vehicle %o tarif %o', info.vehicle, info.tarif);
    }

vehicles.controller.js

.controller('VehiclesCtrl', VehiclesCtrl);

    VehiclesCtrl.$inject = [
        '$scope',
        'vehicles'
    ];

    function VehiclesCtrl(
        $scope,
        vehicles
    ) {
        console.log('vehicles list %o', vehicles);
    }

To access this state, you need to do something like

menu.html

<a ui-sref="vehicles.detail({vehicleId: 1234})">

I purposely did not make vehicles route abstract for illustration purposes. You may want to look into that if you want to create nested state/views. I hope this helps.

Upvotes: 0

Prashant K
Prashant K

Reputation: 909

The problem is with the way this controller code flow works.

$scope.vehicle = {}; //vehicle property is declared and defined as empty obj in the $scope

orderSewaService.vehicleDetail($routeParams.license_plate) This is an ajax call, js calls this method and then goes to the next line , after the end of this method, i.e. console.log($scope.vehicle); without waiting for the call to return and populate $scope.vehicle with your response.


So, try this:

In Controller:

`

$scope.vehicle = {};
orderSewaService.vehicleDetail($routeParams.license_plate).then(function(response){
                $scope.vehicle = response;//rendered in view
                getInfoTarif();
            }, function (error) {
                console.log(error);
            });
function getInfoTarif(){
console.log($scope.vehicle);
orderSewaService.infoTarif($scope.vehicle.zone_id,$scope.vehicle.car_class_id).then(...);
}

`

Upvotes: 0

Sajeetharan
Sajeetharan

Reputation: 222522

You need to declare $scope.vehicle outside the function call,

somewhere in your controller at the begining,

If it's an array

$scope.vehicle =[];

Upvotes: 2

Related Questions