Exposing AngularJS directive property value to parent controller - angularjs

I am working on an AngularJS app. I am trying to write a reusable component to use throughout my app. For the sake of demonstration, we'll just use a text box. I've created a fiddle of my attempt here. Basically, I'm trying to use a control like this:
<div ng-app="myApp">
<div ng-controller="myController">
<my-control textValue="{{controlValue}}"></my-control>
<br />
You entered: {{controlValue}}
</div>
</div>
Unfortunately, I cannot figure out how to bind a property between the scope of the controller and the scope of the directive. I'm not sure what I'm doing wrong in my fiddle. Can someone please tell me what I'm doing wrong?
Thank you!

You have created directive with isolated scope and you are trying to print value from isolate scope. It isn't right, you can write your directive like this, without isolated scope:
return {
restrict: 'EAC',
template: '<input type="text" ng-model="controlValue"></input>'
};
if you want to setup directive with isolated scope, you should isolate your scope then use $watch for do changes

You were not so far, but you need to be carefull when using {{}}
Remove braces and don't use camelNotation for text-value attribute :
<div ng-app="myApp">
<div ng-controller="myController">
<my-control text-value="controlValue"></my-control>
<br />
You entered: {{controlValue}}
</div>
</div>
Use ng-model attribute :
angular.module('ui.directives', []).directive('myControl',
function() {
return {
restrict: 'EAC',
scope: {
textValue: '='
},
template: '<input type="text" ng-model="textValue"></input>'
};
}
);

Related

ngTransclude directive doesn't work, can't realize where I'm wrong

Trying to use ngTransclude first time to make custom directive, to achieve the floating label functionality as shown here: Floating label pattern — Angular JS, but it doesn't work.
Here is my directive code:
.directive('floatingLabel', function () {
return {
restrict: 'A',
scope: {
label: '#',
value: '='
},
transclude: true,
templateUrl: 'floating-label-template.html'
}}
)
Directive's template:
<div class="field">
<label ng-show="value" class="show-hide">{{label}}</label>
<div ng-transclude></div>
</div>
I'm trying to use it in the following way:
<input floating-label label="Floating" value="floatingDirective" type="text" class="form-control" ng-model="floatingDirective"/>
Plunker with my code: https://plnkr.co/edit/MC8G4H3B9zEleaBZ7ijJ?p=preview
P.S. I'm using AngularJS 1.4.9
Fixed plunker.
Read this : What is ng-transclude
Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
Why your code not working: you have nothing to be 'transclude'.
A general markup of use directive with ng-transclude may like this:
<directive-with-ng-transclude>
<node-to-transclude></node-to-transclude>
</directive-with-ng-transclude>
After compiled, <node-to-transclude></node-to-transclude> will be appended to the template of your directive where you put ng-transclude.
Notice : ng-model inside ng-transclude , that's why I use a dotted ng-model floatingDirective.

How to embed an html page using angular directive

I am creating an angular.js application.
I have written a html page and wants to put it under div using directive
<div data-(<directive-name)>
</div>
DxPDictionary.directive('import', [function () {
return {
restrict: 'A',
templateUrl: 'template/Import.html',
scope: false,
}
It's not working, is this approch is right or should use another way to achieve this
<body ng-controller="userCtrl">
<div class="container">
<div ng-include="'myUsersList.html'"></div>
<div ng-include="'myUsersForm.html'"></div>
</div>
</body>
use like this.
<div data-directive-name>
</div>
DxPDictionary.directive('dataDirectiveName', [function () {
return {
restrict: 'A',
templateUrl: 'template/Import.html',
scope: false,
}
your directive name dataDirectiveName in directive definition in camel case format and directive name data-directive-name on DOM should match.
You can use ng-include if you are not creating reusable components using directive and want use is as only html of the page.
There is already a directive for this purpose. You do not need to create your own.
https://docs.angularjs.org/api/ng/directive/ngBindHtml
Ashley's answer is good if you keep your html in a file. If you dynamically generate your html, you can use ng-bind-html directive.

Ways to access element controllers (eg. ngModel & form)

I have a directive that is always placed inside <form> on elements that wrap form elements (input/select/etc), let's assume directive is called wrapper:
<form>
<something>
<wrapper>
<input />
</wrapper>
</something>
</form>
And from within this directive I need to access both formController and ngModelController. I know I can require: ^form in wrapper's directive definition object, but I still need access to ngModelController. I found two ways to achieve it:
childFormControl.controller('ngModel')
childFormControl.data('$ngModelController')
// also for controller I could use this, instead of require
childFormControl.closest('form').controller('form')
childFormControl.closest('form').data('$formController')
My question is : is it considered a hack to use controller or data methods to access the controller or is it safe and considered as usage of public Angular API? I did not find any examples on Angular documentation with this approach.
<body ng-controller="ngModelController ">
<form>
<something>
<wrapper>
<input />
</wrapper>
</something>
</form>
</body>
Js file
(function(){
var app = angular.module('ngModelController ', function(){
//Your main controller
});
app.directive('wrapper', function(){
return {
restrict : 'E',
controller : function(){
//Your form controller actions
},
controllerAs : 'formController'
};
});
})();

angular trasnclude always adds as child, sibling required

I would like to do the transclude equivalent of element.insertAfter. What I am getting is basically element.appendChild. I would like the new element to share the same parent as the directive's element.
I would like
<div>
<input with-button></input>
</div>
to become
<div>
<input></input>
<button></button>
</div>
but I get instead
<div>
<input>
<button></button>
</input>
</div>
My directive's template looks like
<ng-transclude></ng-transclude>
<button></button>
and the directive looks like
angular
.module('appy')
.directive('withButton', withButton);
function withButton() {
return {
restrict: 'A',
transclude: true,
templateUrl: 'path/to/template'
};
}
According to the docs this should work. What am I missing?
First thing, everything you declare as directive template will be put inside the element on which the directive is used. So in your case your template:
<ng-transclude></ng-transclude>
<button></button>
Will go inside the:
<input with-button></input>
So, no wonder the button finishes inside your input.
Second thing, setting { transclude: true } means "get everything from inside the element on which this directive is applied, and put it inside the element in the directive template on which ng-transclude is used", in this case nothing since there is nothing inside
<input with-button></input>
(it has no children).

ngModel doesn't change the original variable when in a custom directive with ngInclude

The variable inside the directive changes but outside the directive it doesn't change. Here is the actual code:
main.html
<div class="row" ng-repeat="row in template">
<fx-widget type="{{row.type}}" value="post[row.name]"></fx-widget>
{{post[row.name]}}
</div>
app.js
app.directive('fxWidget', function() {
return {
restrict: 'E',
scope: {
value: '='
},
link: function($scope, $element, $attributes) {
$scope.typeUrl = '/partials/' + $attributes.type + '.html';
},
template: '<div ng-include="typeUrl"></div>',
};
});
partials/text.html
<input type="text" ng-model="value">
Here are my tests and notes on finding the problem:
First I tested to see maybe the ngModel doesn't like binding the value through dictionary/array, so I added the following in main.html:
<input ng-model="post[row.name]"> {{post[row.name]}}
This one worked.
I tested to see if the problem is at ng-include by changing the template variable in the directive:
template: '<input ng-model="value">
and this one actually worked, so the problem is in ng-include
After digging deeper I realized that the ng-include doesn't even send the data back to the directive:
template: '<div ng-include="typeUrl"></div> {{value}}'
// ^^ doesn't work
However inside the partial file it works:
partials/text.html
<input type="text" ng-model="value"> {{value}}
What I am guessing is that ng-include creates a copy of the scope and that's why it doesn't change in the parent scope. How can I make it change the scope?
Also an offtopic question. How can I get rid of ng-include alltogether and manually load the partials? The templateUrl parameter can accept a function with attributes but it doesn't compile the data binds to actual variables, so that's out of the question.
Thank you!

Resources