ngBootbox icon indicating copy to clipboard operation
ngBootbox copied to clipboard

Can't access controllers scope from template that is loaded by ngBootBox

Open ghost opened this issue 10 years ago • 11 comments

I can't resolve issue. Tried to use service and directive with custom dialog. Problem is that i cant acces Controller's $scope form template.

At example, if i will create $scope.model { param: 'value' } and will try to access it from ngbootbox loaded template, it will be null. I also tried to add $parent.model.param but stil cant access. Also I can't validate form in template. Everything works only if I specify in controller $rootScope everywhere instead of $scope.

My sample Code:

Controller:

angular.module('app.transfers')
    .controller('MyController', function ($scope, $rootScope, $ngBootbox) {

        $scope.model = {
            param: 'some value'
        };

        $scope.transferDialogButtons = {
             success: {
                 label: 'Cancel',
                 className: 'btn-default',
                 callback: function(result) {
                    return true;
                 }
             },
             main: {
                label: 'Confirm',
                className: 'btn-danger',
                callback: function() {
                    return $scope.executeAction();
                }
            }
        };

        $scope.executeAction = function () {
            $rootScope.$broadcast('show-errors-check-validity'); // form validation works only if $rootScope is specified
        };
    });

Html

<button class="btn btn-primary"
        ng-bootbox-title="Title"
        ng-bootbox-custom-dialog
        ng-bootbox-custom-dialog-template="views/transfers/_partials/dialog.html"
        ng-bootbox-buttons="transferDialogButtons">
    <i class="fa fa-exchange"></i> Button Title
</button>

Template

<form class="form-horizontal" name="sampleForm" role="form" novalidate>

    <div class="form-group" show-errors>
        <label for="param" class="col-sm-4 control-label">Param:</label>
        <div class="col-sm-8">
            <input ng-model="model.param" name="param" type="text" class="form-control" required>
            <p class="help-block" ng-show="sampleForm.destination.$error.required">Error Message 1</p>
        </div>
    </div>
</form>

ghost avatar Jul 21 '15 13:07 ghost

Hi,

In new version there is options to add scope to custom dialog using ng-bootbox-options directive. But it is not documented yet.

<button class="btn btn-primary"
        ng-bootbox-title="Title"
        ng-bootbox-custom-dialog
        ng-bootbox-custom-dialog-template="views/transfers/_partials/dialog.html"
        ng-bootbox-options="dialogOptions">
    <i class="fa fa-exchange"></i> Button Title
</button>

Controller:

angular.module('app.transfers')
    .controller('MyController', function ($scope, $rootScope, $ngBootbox) {

        // your staff

        $scope.dialogOptions= {
            scope: $scope,
            buttons: {
                 success: {
                     label: 'Cancel',
                     className: 'btn-default',
                     callback: function(result) {
                        return true;
                     }
                 },
                 main: {
                    label: 'Confirm',
                    className: 'btn-danger',
                    callback: function() {
                        return $scope.executeAction();
                    }
                }
            }
        };

        // your stuff
    });

Note: I move your buttons to options (make setup on one place). Could you test it with this setup?

vlapo avatar Jul 21 '15 13:07 vlapo

@vlapo Thanks for fast reply. Now I can access to scope variables. Everything works except I can't load array of data into ui-select which is located in template that is loaded by ng-bootbox.

If i place this code into template:

<ui-select ng-model="model.wallet" theme="bootstrap" class="ui-select">
    <ui-select-match placeholder="Select Wallet">{{ $select.selected.full_name }}</ui-select-match>
    <ui-select-choices repeat="wallet in wallets | filter: $select.search">
        <div ng-bind-html="wallet.full_name | highlight: $select.search"></div>
    </ui-select-choices>
</ui-select>

Choices doesn't load into ui-select, but if I place same code into my html, below ngbootbox modal button, which is in one scope with controller, then choices are loaded into ui-select.

Controller code:

$scope.model = { wallet: null };
$scope.wallets = null;
WalletService.getResource().get({ }, function (response) {
    $scope.wallets = response.data.wallets;
});

ghost avatar Jul 21 '15 14:07 ghost

I think it is because dialog body is compile with your scope only on creation of dialog.

So your $scope.wallets are fill with data async (response from server) and new value of wallets is not reflected in template.

I have this issue before and I take out this functionality to separate controller.

Template

<div ng-controller="MyDialogController" ng-init="initWallets()">
    <ui-select ng-model="model.wallet" theme="bootstrap" class="ui-select">
        <ui-select-match placeholder="Select Wallet">{{ $select.selected.full_name }}</ui-select-match>
        <ui-select-choices repeat="wallet in wallets | filter: $select.search">
            <div ng-bind-html="wallet.full_name | highlight: $select.search"></div>
        </ui-select-choices>
    </ui-select>
</div>

Controller

angular.module('app.transfers')
    .controller('MyDialogController', function ($scope, WalletService) {

        $scope.wallets = null;

        $scope.initWallets = function() {
            WalletService.getResource().get({ }, function (response) {
                $scope.wallets = response.data.wallets;
            });
        }
    });

Try this way :)

@reinos, @eriktufvesson - What do you think about this issue? I dont have experience with $compile and there is question if $scope changes have to be reflected after dialog creation.

vlapo avatar Jul 21 '15 15:07 vlapo

@ddctd143 Maybe this will work:

$scope.model = { wallet: null };
$scope.wallets = WalletService.getResource().get({});

But I don know. It is only idea :) Feel free to try it.

vlapo avatar Jul 21 '15 15:07 vlapo

@vlapo Is there a way to disable ngbootbox main button while callback function is running, because if main button fires callback function, it still can be pressed many times before dialog is closed.

main: {
    label: 'Submit',
    className: 'btn-danger',
    callback: function() {
        return $scope.doSomething();
    }
}

How I could access button's html to add custom data params ? If i had access to button, I could add bootstrap's data-loading-text and btn-loading="loadingState" to lock button while callback is running.

Maybe this question isn't releated to ng-bootbox, but I'm new to angular

ghost avatar Jul 21 '15 15:07 ghost

Do you resolve issue before (if yes, which solution)?

I dont have info about functionality like this. Maybe new feature request.

In custom dialogs I always use my own buttons in template because I like to control all in dialog (and use $ngBootbox.hideAll() to close dialog) :)

vlapo avatar Jul 21 '15 16:07 vlapo

@vlapo I also use custom dialog with custom buttons. Consider this example:

main button in ng-bootbox-dialog fires callback $scope.serverCallback() which sends something to server. While callback is sending ngbootbox dialog will be opened, and user can click many times to button and fire same function again and again. How do you lock submit button, while callback is running ?

$scope.transferDialogOptions = {
    scope: $scope,
    buttons: {
        main: {
            label: 'Submit Dialog',
            className: 'btn-danger',
            callback: function() {
                return $scope.serverCallback();
            }
        }
    }
};

$scope.serverCallback = function() {
    if ($scope.form.$valid) {
        $scope.submitLoadingState = true;

        SomeService.store($scope.model, function (transfer) {

            // While this function is running ( sending something to server... )
            // Dialog will be opened, and "Submit Dialog" can be pressed many times

            return true; // Closes dialog
        });
    }
    return false;
};

How to resolve this issue ?

ghost avatar Jul 21 '15 16:07 ghost

Could you answer the first question please?

You dont understand :) I dont use buttons option. I have own buttons in dialog template.

E.g. dialog tepmplate

<div ng-controller="MyDialogController" ng-init="initDialog()">
    <form ng-submit="submitFunc()">
        <!-- som form inputs and so on -->
        <input type="submit" value="Submit" />
        <button type="cancel" ng-click="cancelFunc()">Cancel</button>
    </form>
</div>

MyDialogController

angular.module('app.transfers')
    .controller('MyDialogController', function ($scope, $ngBootbox) {

        $scope.initDialog= function() {
            //some stuff
        }

       $scope.cancelFunc= function() {
            //close dialog
             $ngBootbox.hideAll();
        }

        $scope.submitFunc= function() {
            //some stuff

            // on success submit close bootbox dialog
            $ngBootbox.hideAll();
        }
    });

This is little bit more stackoverflow discusion :) not github issue.

vlapo avatar Jul 21 '15 16:07 vlapo

Thanks, will dig into it.

ghost avatar Jul 21 '15 16:07 ghost

I have same problem. I get response from server and try to change the $scope but it doesnt works - it changes but right after the $scope keeps reverting to old value.

Update: Ok now it works. I needed to use $watch and window.localStorage

Hiieu avatar Sep 28 '15 09:09 Hiieu

I solved in this way on the callback function:

.... callback : function(){ $scope.$apply(function(){ ///$scope.val1 = val2; }); }

robertoforlani avatar Oct 26 '15 08:10 robertoforlani