Search code examples
javascriptangularjsangularjs-material

Controller's variable value isn't updated in Angularjs material Toast template


I am trying to use the 'toast' component of AngularJS Material inside a simple Angularjs app.

The documentation is very vague and doesn't even follow its own rules (for example, the necessary use of 'md-actions' class for action buttons). Anyhow, the problem is as follows:

I have created a 'Preset' for my toast with the following config:

$mdToastProvider.addPreset('docEditPreset', {
            options: function () {
                return {
                    templateUrl: 'App/Components/Document_Edit/DocumentEditToast.html',
                    hideDelay: 1200,
                    position: 'bottom right',
                    toastClass: 'document-edit-toast',
                    controller: 'DocumentEditController',
                    controllerAs: 'vm'
                };
            }
        });

And the template for toast is:

<md-toast>

    <span class="md-toast-text">{{ vm.toastText }}</span>

</md-toast>

As it is shown in the code above, I have a variable named vm.toastText inside the template's <span> tag which resides in DocumentEditController and is supposed to be visible in the toast.

The code for DocumentEditController:

vm.toastText = '';

function showToast() {
            vm.toastText = 'I AM A TOAST!';
            $mdToast.show(
                $mdToast.docEditPreset()
            );
        }

(I should mention that vm is the $scope of the controller. The toast config has also been named the same for consistency.)

So the idea is to change the value of vm.toastText before running the toast function. I was hoping to get the updated value inside my toast's template. At the moment, the toast seems to only show the initial value of vm.toastText which is an empty string.

How can I update the value of my variable inside the DocumentEditController and use it in the toast template?

Demo on CodePen


Solution

  • For anyone who is stuck at managing a problem like this, I found a workaround.

    Instead of using my main controller (DocumentEditController in my question), I created a new controller, for example ToastController, and then used locals to pass in the variables I needed.

    So the function in DocumentEditController became:

    function showToast(message) {
                $mdToast.show({
                    templateUrl: 'App/Components/Shared/Toast/ToastTemplate.html',
                    hideDelay: 1200,
                    position: 'bottom right',
                    controller: 'ToastController',
                    controllerAs: 'vm',
                    locals: {
                        message: message
                    }
                });
            }
    

    and ToastController:

    function ToastController($scope, $mdToast, message) {
    
            var vm = this;
    
            //=== Variables ===//
            vm.message = message;
    
            //=== Function declarations ===//
            vm.closeToast = closeToast;
    
            //=== Function implementations ===//
    
            function closeToast() {
                $mdToast.hide();
            }
    
        }
    
    ToastController.$inject = ['$scope', '$mdToast', 'message'];
    

    HTML template:

    <md-toast>
    
        <span class="md-toast-text">{{ vm.message }}</span>
    
        <md-button ng-click="vm.closeToast()" class="md-action md-icon-button">
            <md-icon class="md-light">close</md-icon>
        </md-button>
    
    </md-toast>
    

    I completely removed the Preset I was trying to create in my app's config and instead declared the toast in my main controller (DocumentEditController).

    Now inside my main controller, I can simply call the showToast(message) function with the desired message - be it a string or a variable containing a string.