0

I have an app that has been written in AngularJS, and am currently trying to add the functionality to hide the headings of some widgets displayed on one of the web pages when the user selects a checkbox to indicate that they should be hidden.

At the moment, I have a page that displays a number of widgets- on the 'heading' of each widget, there is a 'Settings' button. When the user clicks the Settings button, a dialog box opens up on top of the current page (i.e. the user does not navigate to another page- the URL does not change at all). That dialog box contains a form with a number of input fields- one of which is a checkbox that I want to use to 'hide' the headings of all of the widgets on the webpage.

I have been following the example at: https://docs.angularjs.org/api/ng/directive/ngHide to try and do this, but can't quite seem to get it working...

I have added the ng-hide attribute to my HTML element, as in the example:

<div data-ng-if="widget.name === 'tag-box'" ng-hide="hideWidgetHeading"> <!-- class="ng-hide"-->
    <div class="divider"></div>
    ...

    <div class="divider"></div>
    <div class="row ui-checkbox-row">
        <label class="col-sm-4 col-xs-6" data-i18n="Hide widget heading:"></label>
        <div class="col-sm-8 col-xs-6">
            <label class="ui-checkbox">
                <input type="checkbox" name="noWidgetHeading" id="noWidgetHeading" ng-true-value= "'YES'" ng-false-value= "'NO'" ng-change="hideWidgetHeading()" ng-click="hideWidgetHeading()" ng-checked="hideWidgetHeading" ng-model="viewModel.hideWidgetHeading">
                <!-- ng-model="viewModel.hideWidgetHeading" -->
                <span></span>
            </label>
        </div>
    </div>
</div>

I defined the hideWidgetHeading() function in the ctrl.js file as follows:

function hideWidgetHeading(){
    if($scope.widgetHeadingCheckbox==false) {
        $scope.$watch('noWidgetHeading', function() {
            $scope.hideWidgetHeading = true; 
            console.log("Value of hideWidgetHeading: ", $scope.hideWidgetHeading);
        });
        return true; 
    } else {
        console.log("hideWidgetHeading() else called (Widget/ctrl.js line 440) ");
        $scope.$watch('noWidgetHeading', function() {
            $scope.hideWidgetHeading = false; //document.getElementById('noWidgetHeading');
        });
        return false; 
    }

    if($scope.hideWidgetHeading) {
        console.log("hideWidgetHeading is true- hide the widget heading: ");

    }
    return $scope.hideWidgetHeading;
}

and I have added the following CSS to my widgets.scss file:

.animate-show-hide.ng-hide {
  opacity: 0;
}

.animate-show-hide.ng-hide-add,
.animate-show-hide.ng-hide-remove {
  transition: all linear 0.5s;
}

.umw-tag-box {
  opacity: 1;
}

When I load my page as it is presently, when I click the Settings button, the dialog opens up. If I then check the 'Hide widget heading' checkbox, and click Submit, the debug that I have added displays the following in the console:

Value of hideWidgetHeading: true

which tells me that the code inside the $scope.$watch(...){...} function is running.

However, if I click the Settings button, and then either don't check the 'Hide widget heading' checkbox, or check it and uncheck it again, and then click Submit, I get the same true value displayed in the console debug, which indicates that the code inside the $scope.$watch(...){...} function is running regardless of whether the 'watched' element changes or not.

Questions

  1. How can I ensure that the code inside the $scope.$watch(...){...} only runs when the 'watched' element (i.e. the checkbox) has its value changed?

  2. How do I actually 'call' the CSS that I've added to hide the HTML elements on the particular HTML that I want to hide? Or how do I make that CSS 'apply' to the HTML elements that I want to hide?

Edit

I changed the HTML for the checkbox to:

<input type="checkbox" ng-model="checked" name="noWidgetHeading" id="noWidgetHeading">

as suggested, and when I now browse to my page, and open the dialog, it displays the widget as I expect:

widget

When I click the 'Settings' button on the widget, the 'Configure Item' dialog opens up on top of the page:

Configure item dialog

But when I select the 'Hide widget heading' checkbox, it actually hides the 'Tag' label & input box from the dialog:

Checkbox hides tag element

The element I want to hide is actually displayed on the page from which the dialog box is opened, not on the dialog box itself... but I can't seem to work out how I can hide that using a control on the dialog... Any suggestions?

Noble-Surfer
  • 3,052
  • 11
  • 73
  • 118
  • have you tried with `ng-hide="hideWidgetHeading()"` (round brackets). I noticed too that you have the same name for variable in the scope, maybe that leads to unexpected behaviour, you have to choose if you use a scope var to hide (without brackets, but you need to call the function) or with your function (in this case, the function should be in the controller scope) – Kaddath Jul 25 '17 at 15:04
  • Where? On the ` (angular-touch.js:440) at HTMLButtonElement.dispatch (jquery.js:4435) at HTMLButtonElement.r.handle (jquery.js:4121)` – Noble-Surfer Jul 25 '17 at 15:14
  • Same name for which variable in the scope? – Noble-Surfer Jul 25 '17 at 15:15
  • i'll have a look later, a little hurry now. you're right, hadn't seen the right part of the checkbox because the line is long. By the way, knowing this, what is written as the checkbox model should be the same as in the ng-hide. Then you shouldn't need the onchange functions and your function at all, the value being updated by the model.. – Kaddath Jul 25 '17 at 15:32

1 Answers1

0

So, this should work, it is even the first example shown in their docs, with your code it will be:

<div data-ng-if="widget.name === 'tag-box'" ng-hide="viewModel.hideWidgetHeading"> <!-- class="ng-hide"-->
    <div class="divider"></div>
    ...

    <div class="divider"></div>
    <div class="row ui-checkbox-row">
        <label class="col-sm-4 col-xs-6" data-i18n="Hide widget heading:"></label>
        <div class="col-sm-8 col-xs-6">
            <label class="ui-checkbox">
                <input type="checkbox" name="noWidgetHeading" id="noWidgetHeading" ng-true-value= "'YES'" ng-false-value= "'NO'" ng-change="logWidgetHeading()" ng-click="logWidgetHeading()" ng-checked="viewModel.hideWidgetHeading" ng-model="viewModel.hideWidgetHeading">
                <!-- ng-model="viewModel.hideWidgetHeading" -->
                <span></span>
            </label>
        </div>
    </div>
</div>

you can keep functions on the events if you wan to log values, but there is no need for hiding. The ng-model directive will update your value and the ng-hide should follow.

function logWidgetHeading(){
    console.log("Value of hideWidgetHeading: ", $scope.hideWidgetHeading);
}

What i was saying about function or var: in some cases, i used to have values from the scope that were not updated, and the solution was to introduce a function to be called to retreive the value. It is what i thought you were trying because ng-hide="hideWidgetHeading" shows the same name as your function: function hideWidgetHeading(){, that's why i first said that the round brackets were missing. So another version would be something like this (without ng-model on purpose, to show an alternate way to modify stuff with your events):

<div data-ng-if="widget.name === 'tag-box'" ng-hide="getHideWidgetHeading()"> <!-- class="ng-hide"-->
    <div class="divider"></div>
    ...

    <div class="divider"></div>
    <div class="row ui-checkbox-row">
        <label class="col-sm-4 col-xs-6" data-i18n="Hide widget heading:"></label>
        <div class="col-sm-8 col-xs-6">
            <label class="ui-checkbox">
                <input type="checkbox" name="noWidgetHeading" id="noWidgetHeading" ng-true-value= "'YES'" ng-false-value= "'NO'" ng-change="toggleWidgetHeading()" ng-checked="isHiddenWidgetHeading">
                <!-- ng-model="viewModel.hideWidgetHeading" -->
                <span></span>
            </label>
        </div>
    </div>
</div>

and the js:

//initialisation to the default value:
$scope.isHiddenWidgetHeading = false;

//function that toggles the value:
$scope.toggleWidgetHeading = function(){
    $scope.isHiddenWidgetHeading = !$scope.isHiddenWidgetHeading;
};

//function to retreive the value:
$scope.getHideWidgetHeading = function(){
    return $scope.isHiddenWidgetHeading;
};

Sorry i was a bit quick in naming vars and such, but you should get what you need here..

Kaddath
  • 5,933
  • 1
  • 9
  • 23
  • Hey, thanks for the answer. The reason I have so many `console.log()` statements at the moment, is purely for development/ debugging purposes- just so that I can see what is called when, what the variable values are at a given point,etc- once I have the feature working, I will remove all of the `console.log()` statements. It's probably just me being dumb, but I can't see where in your answer you are actually hiding anything from the display...? You have `ng-hide="viewModel.hideWidgetHeading"`, but I can't see how that is actually stopping anything from being displayed...? Can you point it out? – Noble-Surfer Jul 26 '17 at 08:22
  • the `ng-hide` directive itself does it. It evaluates what's inside to be true or false (it can even be `ng-hide="true"` but a bit pointless, it will stay hidden). If true, it hides the element automatically. In my first example, there is your var from your checkbox model, it means that when the checkbox changes the value, the ng-hide directive is supposed to update visibility according to this value (i haven't proof checked if checkbox models return booleans, but i think so) – Kaddath Jul 26 '17 at 09:00
  • Ah ok, thanks. I have been tweaking things a bit, and have managed to get something to be hidden when the checkbox is selected- the 'Submit' button on the form doesn't need to be pressed- as soon as the checkbox is checked, the element is hidden, and as soon as you uncheck it, the element is shown again. It appears that this is happening through the CSS, but it's being done on the wrong HTML element at the moment, and I'm not sure how to get it working on the HTML that I actually want to hide... I'll update my OP now. – Noble-Surfer Jul 26 '17 at 10:13
  • you should consider opening a new question, or doing some research with the clues i'll give you, because this is a totally different topic.. If i guess right, those 2 elements are separated and have each one their own scope? If so, what you need is to be able to pass a value from one scope to another (checked from modal to main page). That's a beginning for a search, but that's how i used to do in some apps: you can create a service for global data, that you import in both controllers. Controllers can then send or receive data through it. There might be other solutions, but this worked for me. – Kaddath Jul 26 '17 at 13:16