Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
209 views
in Technique[技术] by (71.8m points)

javascript - AngularJS: Toggle message text based on boolean

I am very new to AngularJS. I have to make what seems like a very small change to our website, but it's stumping me.

  • We have a boolean value in our Django user model, let's call it user.myValue
  • On page load, display text "A" if that boolean is True, and text "B" if it is False
  • In that message text, we have a link element that fires an AngularJS function to open a modal.
  • In the modal, there are two buttons. Clicking them will toggle the boolean value by calling a Django REST endpoint.
  • If the call to that REST endpoint is successful, the value in the database will be updated. (Either way, we close the modal.)
  • On successful update of the database, I now want the message on the main page to be updated to show the correct message based on the new value.

I've managed to get everything up to the last step. I've played with a lot of potential solutions and nothing is quite working. For the element holding the message text,

  • Binding would be ideal because then I can just use $scope.apply() to update the element, but because it's a boolean using ng-bind isn't great: I don't want to just show the user "true" or "false".
  • ng-if is ugly because on page load it displays both messages for a split second and then removes one. I also can't figure out how to get it to re-run the "if" condition when we've had a successful database update.
  • I've played with creating a directive, but that also doesn't seem right.
  • ng-model="user.myValue" ng-value="true" isn't useful because it doesn't conditionally show the message...

Here's my code so far.

Template:

<div ng-controller="myCtrl">
    <div id="modal-my-value-toggle" class="modal">
        <a ng-click="myValueToggle('false')">No</a>
        <a ng-click="myValueToggle('true')">Yes</a>
    </div>
    {% if user.myValue %}
    <div name="myValueTrue">
        Message A: Your value is Yes. <a ng-click="openModal()">click here to change your value</a>
    </div>
    {% else %}
    <div name="myValueFalse">
        Message B: Your value is No. <a ng-click="openModal()">click here to change your value</a>
    </div>
    {% endif %}
</div>

Controller:

function myCtrl ($scope, $http, Notification) {

    $scope.username = context.targetUsername;

    $scope.openModal = function() {
        var $myModal = $('div').find('#modal-my-value-toggle');
        $myModal.modal({
                keyboard: false,
                backdrop: "static"
            });
        $myModal.modal('show');
    };

    $scope.myValueToggle = function(userProvidedValue) {

        // hide the modal
        var $myModal = $('div').find('#modal-my-value-toggle');
        $myModal.modal('hide');

        if (userProvidedValue === 'true') {
            var success = "Your value is now Yes";
        } else {
            var success = "Your value is now No";
        }

        // ping the api to set flag to true
        $http({
            method: 'GET',
            url: '/api/user/' + $scope.username + '/myValue/?myValue=' + userProvidedValue,
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }).then(function(response) {
            Notification.success(success);
        }, function(response) {
            Notification.error("There was an error.");
        });
    };
}

Some other stuff I tried...

This is based on this https://coderwall.com/p/ybbopq/use-ng-value-for-ng-model-with-boolean-values It just displays both messages and isn't really what I want. It's meant to provide a radio input that you can switch between to update the value in $scope.

<div name="myValue_true" ng-model="user.myValue" ng-value="true">
    Message A: Your value is Yes. <a ng-click="openModal()">click here to change your value</a>
</div>
<div name="myValue_false" ng-model="user.myValue" ng-value="false">
    Message B: Your value is No. <a ng-click="openModal()">click here to change your value</a>
</div>

This one is just a different way of deciding which message to display on initial page load. It flashes both messages and then removes one.

<div ng-if="user.myValue">
    Message A: Your value is Yes. <a ng-click="openModal()">click here to change your value</a>
</div>
<div ng-if="!user.myValue">
    Message B: Your value is No. <a ng-click="openModal()">click here to change your value</a>
</div>

I also tried this janky thing in the controller (didn't work):

function myCtrl ($scope, $http, Notification) {

    $scope.username = context.targetUsername;

    $scope.openModal = function() {
        var $myModal = $('div').find('#modal-my-value-toggle');
        $myModal.modal({
                keyboard: false,
                backdrop: "static"
            });
        $myModal.modal('show');
    };

    $scope.myValueToggle = function(userProvidedValue) {

        // hide the modal
        var $myModal = $('div').find('#modal-my-value-toggle');
        $myModal.modal('hide');

        var message_ids = {
            'yes': 'myValue_true',
            'no': 'myValue_false'
        }

        if (userProvidedValue === 'true') {
            var success = "Your value is now Yes";
            var show_message = message_ids['yes']
            var hide_message = message_ids['no']
        } else {
            var success = "Your value is now No";
            var show_message = message_ids['no']
            var hide_message = message_ids['yes']
        }

        // ping the api to set flag to true
        $http({
            method: 'GET',
            url: '/api/user/' + $scope.username + '/myValue/?myValue=' + userProvidedValue,
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }).then(function(response) {
            $('div').find('#' + show_message).show();
            $('div').find('#' + hide_message).hide();
            Notification.success(success);
        }, function(response) {
            Notification.error("There was an error.");
        });
    };
}

Am I going about this completely the wrong way? Am I supposed to be making a directive out of the message element? Or something else? Any help would be greatly appreciated. Thank you!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The reason behind the message flashing and then being removed in your ng-ifs is that user.myValue isn't defined when it first renders the page. This can be fixed by doing the following:

Add the following function to the controller

$scope.checkMyValue = function() {
    if (typeof $scope.user == 'undefined') {
        return false; // Prevent error on check of undefined user
    } else {
        return typeof $scope.user.myValue != 'undefined';
    }        
};

You can then change your ng-if to be

ng-if="!user.myValue && checkMyValue()"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...