1

I am new to Stackoverflow. I'm also new to AngularJS. I apologize if I'm not using this correctly. Still, I'm trying to create a UI control with AngularJS. My UI control will look like this:

+---------------------+
|                     |
+---------------------+

Yup. A textbox, which has special features. I plan on putting it on pages with buttons. My thought is as a developer, I would want to type something like this:

<ul class="list-inline" ng-controller="entryController">
  <li><my-text-box data="enteredData" /></li>
  <li><button class="btn btn-info" ng-click="enterClick();">Enter</button></li>
</ul>

Please note, I do not want buttons in my control. I also want the enteredData to be available on the scope associated with child controls. In other words, when enterClick is called, I want to be able to read the value via $scope.enteredData. In an attempt to create my-text-box, I've built the following directive:

myApp.directive('myTextBox', [function() {
    return {
        restrict:'E',
        scope: {
          entered: '='
        },
        templateUrl: '/templates/myTextBox.html'
    };
}]);

myApp.controller('myTextBoxController', ['$scope', function($scope) {
    $scope.doSomething = function($item) {
        $scope.entered = $item.name;

        // Need to somehow call to parent scope here.
    };  
}]);

myTextBox.html

<div ng-controller="myTextBoxController">
    <input type="text" class="form-control" ng-model="query" placeholder="Please enter..."  />
</div>

entryController.js

myApp.controller('entryController', ['$scope', function($scope) {
  $scope.enteredData = '';
  $scope.enterClick = function() {
    alert($scope.enteredData);
  };
});

Right now, I have two issues.

  1. When enterClick in entryController is called, $scope.enteredData is empty.
  2. When doSomething in myTextBoxController is called, I do not know how to communicate to entryController that something happened.

I feel like I've setup my directive correctly. I'm not sure what I'm doing wrong. Can someone please point me in the correct direction.

2 Answers 2

1

Three suggestions for you.

1) You really shouldn't create a directive with a template that references a controller defined elsewhere. It makes the directive impossible to test in isolation and is generally unclear. If you need to pass data into a directive from a parent scope use the isolate scope object on your directive to bind to that data (Note how the directive template doesn't have a controller) http://jsfiddle.net/p4ztunko/

myApp.directive('myTextBox', [function () {
    return {
        restrict: 'E',
        scope: {
            data: '='
        },
        template: '<input type="text" class="form-control" ng-model="data" placeholder="Please enter..."  />'
    };
}]);

myApp.controller('entryController', ['$scope', function ($scope) {
    $scope.enteredData = 'Stuff';
    $scope.enterClick = function () {
        alert($scope.enteredData);
    };
}]);

<div>
    <ul class="list-inline" ng-controller="entryController">
        <li>{{enteredData}}
            <my-text-box data="enteredData" />
        </li>
        <li>
            <button class="btn btn-info" ng-click="enterClick();">Enter</button>
        </li>
    </ul>
</div>

2) Don't obfuscate HTML when you don't need to. One of the goals of angular is to make the markup more readable, not replace standard elements with random custom elements. E.g. If you want to watch the value of the input and take action depending on what it is you could do that in the linking function (Note: still not referencing an external controller) http://jsfiddle.net/Lkz8c5jo/

myApp.directive('myTextBox', function () {
    return {
        restrict: 'A',
        link: function(scope, element, attrs){
           function doSomething (val) {
              alert('you typed ' + val);
           }
           scope.$watch(attrs.ngModel, function (val) {
               if(val == 'hello'){
                   doSomething(val);
               }
           });
        }
    };
});

myApp.controller('entryController', ['$scope', function ($scope) {
    $scope.enteredData = 'Stuff';
    $scope.enterClick = function (data) {
        alert('You clicked ' + data);
    };
}]);

<div>
    <ul class="list-inline" ng-controller="entryController">
        <li>{{enteredData}}
            <input type="text" ng-model="enteredData" my-text-box />
        </li>
        <li>
            <button class="btn btn-info" ng-click="enterClick(enteredData)">Enter</button>
        </li>
    </ul>
</div>

3) Pass data into controller functions from the UI instead of referencing the $scope object in the function like in ng-click="enterClick(enteredData)" It makes testing easier because you remove the $scope dependency from that method

Sign up to request clarification or add additional context in comments.

Comments

0

$scope.enteredData is empty because you're not using the correct scope. The $scope in entryController is not the same $scope as in myTextBoxController. You need to specify one of these controllers on your directive, and then use that to reference the proper scope.

It seems like you should move the enterClick and corresponding button into your directive template. Then move the enter click into your text box controller and you will be able to reference $scope.enteredData.

You can notify a parent scope of a change by using $emit. (This is in reference to your comment "// Need to somehow call to parent scope here.")

Furthermore, you may have an issue of not using the proper variable. In myTextBox directive, you declare $scope.entered, yet you are effectively setting $scope.data equal to the value of enteredData in the html.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.