1

Plunkr

I have a simple auto-complete dropdown. It works fine when I use only controller.

I want to Make it reusable,so I made a custom directive with isolated scope.

But the problem is when I type on search text box, it does not call the controller function which is assigned to ng-change instantly. when I start typing once again, it calls the function. Again it takes the value what I typed before not the current model value.

I am new to custom directives... I really don't know how to update model instantly and pass from directive scope to controller scope.

Another think I can't able to pass the function parameter from html to controller function.

I think I have to use $apply or $digest somewhere.. But where and how should I use ?

autofillApp.directive('autofillDropdown', function($rootScope) {

    return {

        restrict: 'A',
        templateUrl: "dropdowntemplate.html",
        replace: true,
        scope: {
            'items': '=autofillItems',
            'selected': '=autofillSelected',
            'change': '&autofillChange',
            'focused': '=autofillFocus',
            'onSelect': '&autofillOnselect'
        },
        link: function(scope, element, attr) {
            //console.log(scope.$$watchers);
            //console.log(element);
            //console.log(attr);
            return
        },
        compile: function(element, attributes) {

            var linkFunction = function($scope, element, attributes) {
                $scope.$apply();
            }
            return linkFunction;
        }

    };
})

Here is My Plunkr : Plunkr

3 Answers 3

1

Hey I checked out your approach and fixed your problem.

Your "change" function gets called with the "ng-change" of the input field. That's okay right. But the ng-model is not updated at this moment. Therefore just provide a parameter with the value of the input.

ng-change="change({searchText:selected})"

You need to provide a JSON Object with the right property name. In this case we route out of the isolated scope so we need to call it that way (with the same property name "searchText"):

change="SearchCurrencyOnSearchTextChange(searchText)"

So the final "change" function should look like this:

$scope.SearchCurrencyOnSearchTextChange = function (searchText) {
    if (searchText === null || searchText === '' ||searchText ===undefined) {
        $scope.IsFocused = false;
    }
    else {
        $scope.IsFocused = true;
        $scope.searchCurrencies = $scope.GetFilteredData(searchText);
    }
};

I also removed some of your css hide and show approaches. If you use ng-show and jquery to display/hide things, it soon will blow your mind. Try to stick with one.

Also I changed your directive from "attribute" to "element" directive ;D

https://plnkr.co/edit/8sNVFLGOfEcjeLw58Wb6?p=preview

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

1 Comment

working fine.Thanks for providing complete solution.
1

I tried to move the template, and controller into your directive so you can reuse it. I created a controller alias for the ViewModel assigned to the controllerAs property. Hopefully this helps guide you in the right direction:

// Main App
var app = angular.module("app", ['autofillApp']);

app.controller("appCtrl", function ($scope, $http) {
    // Main app controller.
});


//Directive App.........................
var autofillApp = angular.module('autofillApp', []);

autofillApp.directive('autofillDropdown',function(){


    var AutoFillCtrl = function() {

      var vm = this;

      // Get autofill data for country...
    vm.SearchCurrencyOnSearchTextChange = function () {
        if (vm.searchTextCurrency === null || vm.searchTextCurrency === '' || vm.searchTextCurrency ===undefined) {
            vm.IsFocused = false;
            document.getElementById('currencySearchList').style.display = "none";
        }
        else {
            vm.IsFocused = true;
            document.getElementById('currencySearchList').style.display = "block";

            vm.SearchCurrencies = vm.GetFilteredData(vm.searchTextCurrency);
        }
    };

    //Get autofill Result on search for Currency
    vm.AutoFillCurrency = function (currency) {
        vm.IsFocused = false;
        document.getElementById('currencySearchList').style.display = "none";
        vm.searchTextCurrency = currency.Name;
    };

    vm.data = [

        {
            Id: 1,
            Name:"Dollar"
        },
        {
            Id: 2,
            Name: "Pound"
        },
        {
            Id: 3,
            Name: "Rupee"
        },
        {
            Id: 4,
            Name: "Yan"
        },

    ];

    vm.GetFilteredData = function (name) {
        var filteredItems = [];
        name = name.toLowerCase();
        for (var i = 0; i < vm.data.length; i++) {
            var result = vm.data[i].Name.toLowerCase().search(name);
            if (result != -1) {
                filteredItems.push(vm.data[i]);
            }
        }

        return filteredItems;
    };

    };

    AutoFillTmpl = '<div class="pos_Rel"><input placeholder="Search Currency e.g. dollar,pound,rupee" type="text" ng-change="vm.change()" ng-model="selected" class="form-control width_full" /><ul ng-show="focused && items" id="currencySearchList"><li class="autofill" ng-repeat="result in vm.items" ng-click="vm.onSelect(result)" ng-bind="result.Name"></li></ul></div>';

    return {

    restrict:'A',
    controller: AutoFillCtrl,
    controllerAs: 'vm',
    bindToController: true,
    template: AutoFillTmpl,
    scope: {
        'items': '=autofillItems',
        'selected': '=autofillSelected',
        'change': '&autofillChange',
        'focused': '=autofillFocus',
        'onSelect': '&autofillOnselect'
    }
};

});

Comments

1

Here is working JSFiddle ,need to add watch service..

controller: function($scope){
      $scope.$watch("selected", function(newVal, oldVal){
        $scope.change();
      })
    }

1 Comment

ya. It is working ..thanks.I am accepting walki12 's answer as a approved answer because he also provided the solution for how to pass parameter from function...... :)

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.