Angular js plunkr not working while accessing through iframe - javascript

i am not able to access Model for model in below plunkr, please find plunkr below.please help.
<div ng-controller="PersonCtrl">
<h2>Teens - using external HTML file as template</h2>
<iframe src="teen-external.html"></iframe>
</div>
Here's the Plunkr for any ref.

You have a couple of problems in your example, first the html source was loaded in iframe, which loads it as a simple html and renders it inside the iframe without angular parsing it to do all the mastache interpolation.
To correct this since you've already created a directive that renders the teen-external.html which would allow angular to parse the said html and interpolate the relevant fields. to do this simply use the directive inside your index.html file like.
<teen-internal> </teen-internal>
or
<div teen-internal></div>
Another problem is that you're trying to access a variable/model defined inside the parents $scope which is not possible without going via the $scope.$parent. Even if you do it using the $parent it is considered a really bad practice. To this a bit more elegantly angular provides a sort of model/variable passing from parent to the child, to do this you need to change both the index.html and the teensInternal directive code.
in your index.html
or
<div teens-internal teens="teens"></div>
This sets the teens property on the teensInternal's $scope to the teens from the parent's(PersonCtrl) $scope. Now in your directive code you must define how the binding works for teens property, here you can define it as a read only # also called one way binding (modification done inside teensInternal is not reflected inside the parent controller) or as writable = two way binding (both teensInternal and PersonCtrl share the same object, so the modifications are reflected in both sides) to do this change
scope: {
},
to
scope: {
teens: '=' // or "#" for one way binding
},
This tells the directive that whatever was passed to <teens-internal teens="teens"></teens-internal> through teens="<model's name>" can be used inside the directive's $scope.
Plunkr: plunkr source

Related

Accessing the NG-MODEL from Directives TemplateUrl from Parent HTML file

I will describe my problem in a simple way I can.
I had a Directive called Directive-A and it has a templateUrl named name.html, inside name.html there is a ng-model="name" and I want to access it from my Parent HTML File where the Directive-A is called.
If I illustrate it in a Nested Diagram will goes like this:
Parent HTML File -> Directive-A -> name.html -> ng-model="name"
Edit
Note: I'm trying to access it via pre tag. When I try to use a <pre>{{name.$viewValue}}<pre>, it works. But I know it is not the exact solution to my problem.
I hope there someone who can provide me an answer or idea on how to solve my problem.. I been looking for an answer for this in a long time now, and still I can't fix it..
Edit 2 Added Link to Plunker: https://plnkr.co/edit/6glStzEq5ckZZzph2qLw?p=preview
If your directive Directive-A is isolated then there is no way.
If your directive create scope then you have to modify your template like
ng-model="someobj.name"
and in your "Parent HTML File" controller define that someobj like below
$scope.someobj = {}
If your directive is not craeteing its scope(mean shared scope) then you can simply access that variable in your "Parent HTML File".

Is it possible to compile a modified directive template without using transclusion?

I have been trying to use transclusion to create a directive which makes two copies of it's contents and appends them inside the original template. I have failed in my attempts to modify the two copies before they slotted back into the DOM and I think it's because I have misunderstood how transclusion works.
I have another question here which I don't think is going to be answered because I think the premise may be wrong.
Transclude function needs to modify clone properly
I need to take a new approach to this and I was wondering if it would be sensible to ditch transclusion and get my hands dirty inside a compile function.
My new question is, can you take the contents of "elem", make a couple of copies of it using JQlite then compile them manually against the directive's parent scope and add them back into the original template?
So, if my toolbar directive is used like this, where the contents of the toolbar tag can be any HTML the user wants...
<div ng-controller="myController">
<toolbar>
<form name="formName" submit="myController.submit()">
<div>
... some controls...
</div>
</form>
</toolbar>
</div>
And the template for the directive is this....
<toolbar-inner>
<div class="toolbar">
<div transclude-main></div>
</div>
<div class="overflow">
<div transclude-overflow></div>
</div>
</toolbar-inner>
My compile function of the toolbar directive needs to take a copy of the contents of the element, clone it, rename any forms so that we don't have duplicate form names then compile one copy against the parent controller and slot it into the main slot then do the same with a second copy and slot it into the overflow slot.
The key things is that at the end of it I should have a single directive with two copies of it's contents and my controller should have two forms on it - myController.formName and myController.formName2
Please let me know if I haven't explained something correctly here. I'm pretty sure the solution here should not involve transclusion, hence posting the second question. It is not a duplicate.
If I can explain anything in further detail please ask.
Many thanks.
EDIT:
I have tried to do this in the following Plunkr
https://plnkr.co/edit/eUIdaPiOIISDdXGLBTKJ?p=preview
I have a few problems with this:
A) I am getting a JS error in the console - TypeError: Cannot read property 'childNodes' of undefined
B) I was assuming I could just mess with the template in the pre-compile phase and replace the contents of the directive with new HTML consisting of a new template merged with two copies of the original contents. I can see though that I have to compile them against the $parent scope because my directive uses an isolate scope (although not strictly necessary in this cut down example)
C) I get another error when replacing the original contents of the directive element anyway.
I think I am half way there and hopefully this plunk shows what I an prying to achieve, but i have run out of knowledge.
For completeness, here is the plunk where I tried to do it with transclusion, which didn't work because the transcluded contents are already compiled by the time I started messing with them in the transclude function.
https://plnkr.co/edit/XE7REjJRShw43cpfJCh2?p=preview
You can see the full conversation about this in my previous question:
Transclude function needs to modify clone properly
I got your transcluded example working. See here.
I had to call the below to get it working.
$compile(clone)(scope.$parent);
For the ngTransclude:orphan problem, in this version by compiling just the form elements it works when the child transclude is outside of the form.
This plunker was prior to Angular 1.5 which introduce Tranclusion.
link: function(scope, element) {
if (!element.find('ng-transclude').children().length) {
element.find('button').append('<b style="color: red">Button1</b>');
}
}
Plunker

AngularJS: How to set an attribute to a custom directive

I have a custom directive which holds a <textarea> element along with other HTML elements in its template using templateUrl. This directive should allow a user to type with any Indian Language (using any writing script like devanagri and others). The user will get to select the input language.
This directive will be used like this in my HTML:<keybuddy></keybuddy>
Now my problem is, in my main code, how should I retrieve the text entered in the textarea that is located in the template.html specified by templateUrl? I have the text available in the scope of my link function since I used ng-model on the textarea.
<textarea id="inputField"
placeholder="start typing....."
ng-model="inputText"
rows="5">
</textarea>
In my index.html, I should be able to do something like this:
<keybuddy></keybuddy>
<button onclick="printText()">Show Text</button>
<script>
var printText = function () {
console.log($("keybuddy").value);
}
</script>
How do I do it? Is there any other better way using the power of AngularJS? I went through these posts but wasn't helpful. Or might be I could not understand how to use it in my work. How to set a native attribute from AngularJS directive?, How to get evaluated attributes inside a custom directive
my complete code on github: keybuddy
Note:
I should be able to use this directive anywhere in the application, any number of times.
It should be portable; I should be able to use it in any of my project or any other developer should be able to use it without much
Go Angular :-)
You don't need the use of jQuery here. Angular is sufficient enough. You can change your code like this:
In your View:
<keybuddy model="myInputText"></keybuddy>
<button ng-click="showText()">Show Text</button>
In your View controller:
$scope.showText = function() {
console.log($scope.myInputText);
}
And update your directive to have scope like below (replace your `scope: true):
scope: {
inputText: '=model'
}
Read more on Isolating scope of a directive
You can setup a bi-directional binding to the directive scope. This will allow your directive to change a value in the parent scope, which you can then read from your controller.
In your directives configuration setup the scope property with the name of an attribute to use for the binding, such as:
scope: {
model: '='
}
In your directive's template then you can set the textarea's ng-model to that binding name.
<textarea ng-model="model"></textarea>
In the parent where you use the directive, pass the attribute you configured set to the name of a variable on the scope.
<keybuddy model="inputText"></keybuddy>
Then in your controller you can access the textarea's current content by reading $scope.inputText.
$scope.printText = function(){
alert($scope.inputText);
}
Template:
<button ng-click="printText();">Print text</button>
Since it's already in the scope, you could simply use
console.log($("keybuddy textarea").scope().inputText);
AngularJS version:
console.log(angular.element("keybuddy textarea").scope().inputText);
EDIT: Adapted to match the actual source code.

angularJS executing directive in memory and geting innerHTML

I have created a directive in angularJS as <print-note print-data='printData' id='notePrintDiv'></print-note> this directive will take some object and create a formatted html for printing, but I don't want to show the formatted html in my main html I want the formatted html for printout. so I was hopping if there is any way in angularJS where in I just create the element and pass the scope object to it like angular.element("<print-note print-data='printData' id='notePrintDiv'></print-note>"); or any other way and get its innerHTML.
P.S. I can also achieve the same with making outer html of directive template as display: none but that seems to be a bit hacky way.
The $compile service should be able to do this. Inject it in your controller where you have access to the scope (with printData).
var element = $compile('<print-note print-data="printData" id="notePrintDiv"></print-note>')($scope);
I had to achieve samething in a AngularJS app - I kept the directive for Print-Button and I kept id for the div or HTML block that was targeted to be printed and kept that div/html ng-show=false. I think it's one of the right way to get the required task done.

In AngularJS, how can I nest variable child directive(s) inside a parent directive?

Introduction
For the project I am working on, I am trying to tackle a particular problem in the 'angular way', however I think I must be missing something because no matter what I try I continue to reach brick wall.
The crux of this issue is I am dynamically loading data from a backend that describes different components that are visible to the user. That's not the issue itself, but rather the issue of the particular & proper 'angular' way to turn a list of 'models' describing the components into actually rendered HTML.
Problem
What I am trying to create is basically the following:
Start off with a parent directive that uses ng-repeat for a scoped list called "models", which contains zero or more "components":
<parent-directive ng-repeat="model in models" model="model"></parent-directive>
The ng-repeat directive creates N copies of that original directive with different 'model' arguments (for each object in the $scope.models array).
// this is just for demonstrative purposes, it obviously looks different in source
<parent-directive model="child1"></parent-directive>
<parent-directive model="child2"></parent-directive>
<parent-directive model="child3"></parent-directive>
issue! => The parentdirective gets transformed into a specific child directive depending on data (in this case, called 'type') contained within the javascript object:
<parent-directive model="..."></parent-directive>
turns into
<child-directive-one model="..."></child-directive-one>
or
<child-directive-two model="..."></child-directive-two>
dependent on what the value 'model.type' is.
The child directive then renders into it's own custom HTML (outside the scope of this problem) using data passed to it. If we continued the example from above, that HTML should render into the following (hopefully):
<child-directive-one model="child1"></child-directive-one>
<child-directive-one model="child2"></child-directive-one>
<child-directive-two model="child3"></child-directive-two>'
Followed by (and this is outside the scope of the issue but just to see it through to the end) each directive rendering into its own HTML:
<div>in childDirectiveOne, text is: This is text contained inside child1</div>
<div>in childDirectiveOne, text is: This is text contained inside child2</div>
<div>in childDirectiveTwo, text is: This is text contained inside child3</div>
Source
I've been trying lots of different variations of things to try and get it to work (involving the link function, using $compile, etc), but this source is provided with all of those attempts stripped out. Here's the source I've developed so far:
removed source (was filled with errors). Solution that Scott helped me out with is below:
Conclusion
Thanks for any advice in advance.
Update:
Solution exists here (thanks again to Scott).
I'm not sure exactly why you can't just have a single directive, however something like the following might work. Instead of repeating the parent directive you just pass in the models and have that directive repeat and create each of the child directives.
<parent-directive the-models="models"></parent-directive>
Parent directive template:
<div ng-repeat="model in models"....>
<child-directive ng-if="YOUR CONDITION"></child-directive>
<child-directive2 ng-if="YOUR CONDITION"></child-directive>
</div>

Categories