I wanted to grab the Html DOM inside an element as an string to angular controller. I didn't find good resource online. I have following Html Code:
<div class="form-group ng-controller="straightRunningBeltsCtrl"">
<button class="btn btn-success btn-lg" ng-click="post()">Get Service Factor</button>
<div id="pop-up"><h1>My content here!!</h1></div>
</div>
And I have following JS code
angular.module('straightRunningBelts', [ ])
.controller('straightRunningBeltsCtrl', straightRunningBeltsCtrl)
function straightRunningBeltsCtrl($stateParams, $scope, $http, $sce){
$scope.post= function () {
var template=$sce.trustAsHtml(angular.element(document.getElementById('pop-up')));//Results an error( $sce.trustAsHtml needs string input)
}
Variable template needs to get value from DOM. Right now, angular.element(document.getElementById('pop-up') returns object. I wanted to do sometime like JQuery Does by using html() function here. Any help or reference to it is welcomed.
To retrieve the HTML inside your DOM element, you can use innerHTML. In your case it would be
document.getElementById('pop-up').innerHTML
Working Plunkr
Related
I have a special template problem... I have a array of products, every products have a property "button_code", this property is a result in plain text of HTML laravel template with some angular code inside.
Actually im using a ng-bind-html="product.button_code" inside a and use this template inside a ng-repeat, the html code is correctly inserted in every repeat iteration, but the code is plain text, and I need to "wake up" the ng-controllers ng-clicks etc inside this html
I try with this:
var targets = $('.buy-button-container').toArray();
for (var target in targets) {
console.log($(targets[target]));
$compile($(targets[target]))($scope);
}
$scope.$apply();
But this make the code inside the container (all html code inserted in the ng-bind-html) dissapear of the DOM.
How i can do this?
PD: and yes, im forced to use these template in these product.button_code because special things...)
Thanks
EDIT: This is a piece of code i want to bind:
<button class="buy-link btn btn-default" data-toggle="modal" role="button" ng-controller="BuyController" ng-click="doProduct({'id':'8888','title':'testestest','price':13.99,'currency':'EUR''preorder_enabled':false,'crossedPrice':100,'stock':true,'short_desc':'bla bla bla.','lbonus':false,'bonus_txt':false})">
<span class="left">
<i class="fa fa-cart"></i>
<span itemprop="price">€13.99</span>
</span>
<span class="right">
{{GETIT}}</span>
</button>
Use the transclude function furnished as the second argument of the function created by the $compile service:
app.directive("compileBindExpn", function($compile) {
return function linkFn(scope, elem, attrs) {
scope.$watch("::"+attrs.compileBindExpn, function (html) {
var expnLinker = $compile(html);
expnLinker(scope, function transclude(clone) {
elem.empty();
elem.append(clone);
})
});
};
});
The above directive evaluates the compile-bind-expn attribute as an AngularJS expression. It then uses the $compile service to bind the evaluated HTML to the element. Any existing content will be removed.
Usage:
<div class="buy-button-container" compile-bind-expn="buttonCode">
<p>This Node disappears when expression binds</p>
</div>
Note that the directive uses a one-time binding in the $watch to avoid memory leaks.
The DEMO on JSFiddle
In order to make HTML render you have to use the following function:
$sce.trustAsHtml('<b>Your html</b>');
You will have to inject $sce into your Controller.
If you are doing this in a ng-repeat you will need a function in your controller that does this. Ex:
$scope.transformHTML = function(html) {
return $sce.trustAsHtml(html);
}
in your template...
<div ng-repat="foo in bar">
<div ng-bind-html="transformHTML(foo.html)"></div>
</div>
Anyway, I don't think that the "Angular" magic within your HTML will work.
I have a directive which loads a template with a bunch on input fields. One of which is the jQuery/Bootstrap datepicker.
<my-directive-buttons></my-directive-buttons>
When a user selects/clicks on the datepicker field, the calendar is displayed. I have also attached an ng-click to the input field:
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
On click, the calender is displayed and $scope.addCalendarFooter is called:
app.directive('myDrectiveButtons', function($compile) {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
},
templateUrl: 'controls/input-fields.html',
link: function(scope, elem, attrs) {
},
controller: function($scope) {
$scope.addCalendarFooter = function() {
$('#datepicker').append($('<div></div>').load('myDir/calendar/customFooter.html'));
}
}
}
});
I am successful in appending the contents of customFooter.html to the calendar, however, within customFooter.html are further ng-clicks, which when pressed, are not being called. E.g
customFooter.html
<div>
<button ng-click="controlClick()">Click Me</button>
</div>
Yet, if i move this button out of customFooter.html and in to input-field.html, to test the button logic is correct, the click is called.
I have tried $scope.$apply and $scope.digest after the .append, however i get a 'digest already in progress error'
UPDATE:
Based on comments, below, have tried to remove jQuery and use an 'angular way'
$scope.addCalendarFooter = function() {
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html);
$compile(myEl)($scope)
}
The above inserts my .html template via the ng-include however is it replacing the contents of the datepicker rather than inserting at the bottom of it. Tried .append but that didn't worth either.
You're basically loading the footer manually and bypassing angular completely. Angular doesn't see that you're loading the html and so doesn't compile the html template and bind directives, including ng-click, at all.
You can use ng-include directive that loads the specified template, instead of making a custom one yourself. Or if your directive needs other functionality, just have the ng-include in the directive template itself.
Quoting from your UPDATE:
The above inserts my .html template via the ng-include however is it replacing the contents of the datepicker rather than inserting at the bottom of it. Tried .append but that didn't worth either.
The aforementioned issue is due to using .html() method which inserts HTML to a DOM node and overwrites any existing content of the selected node:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
var myEl = angular.element(document.getElementsByClassName('datepicker');
myEl.html(html); // <== here
$compile(myEl)($scope)
What you are doing with the above logic is that you first select the .datePicker element, then you replace its inner HTML with the .html() method.
As a workaround, you could have used .append() method instead.
NOTE: angular.element() is Angular's wrapper for an element just as in jQuery you had $(). Therefore, using document.getElementByClassName() method is redundant in your case.
Although the above workaround might solve your problem, but it is better to stick to a cleaner and concise approach which AngularJS may offer.
Angularesque Approach
You don't need to load a template partial by programmatically adding/appending the template in a controller function - at least in Angular's way. This way you might end up not binding the angular directive(s) within the dynamically added HTML correctly with a scope.
Instead, just include the partial within the original directive template (with ng-include) and use ngIf or ngShow to display it when the button is clicked.
Therefore, assuming that you've the footer template (customFooter.html) in the original directive template, you can achieve the expected result as in the following:
Directive Template
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group datepick'>
<input type='text' class="form-control" ng-click="addCalendarFooter()"/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div ng-include="myDir/calendar/customFooter.html" ng-if="isCalenderFooterAdded"></div>
Directive Controller
controller: function($scope) {
$scope.addCalendarFooter = function() {
$scope.isCalendarFooterAdded = true;
// or use this if you want to toggle it
// $scope.isCalendarFooterAdded = !$scope.isCalendarFooterAdded ? true: false;
}
}
Plunkr mimicking a similar situation.
What if you include your footer in your template initially but hide it with ng-if / ng-show. Then the function would only change a flag and show the previously hidden footer.
You said that your problem is the fact that after calling $scope.$apply or $scope.digest you get the $digest already in progress error.
A clever way to bypass this is using $evalAsync. One of its biggest advantages is that it knows if it should perform an extra digest cycle of not.
If you're using ng-include don't forget the singlequotes at the begining and end of the path.
Angular doc about ng-include: https://docs.angularjs.org/api/ng/directive/ngInclude
make sure you wrap it in single quotes, e.g. src="'myPartialTemplate.html'"
it should be:
var html = "<ng-include src=\"'myDir/calendar/customFooter.html'\"><\ng-include>";
or:
var html = "<div ng-include=\"'myDir/calendar/customFooter.html'\"><\div>";
but not:
var html = "<div ng-include src=\"myDir/calendar/customFooter.html\"><\div>";
This question already has answers here:
Insert HTML into view from AngularJS controller
(17 answers)
Closed 7 years ago.
Actually im searching about how i can transform my variable into Html, this variable contain a embed code from instagram.
in my controller
instaembed.controler "instaCtrl", ($scope, $http) ->
#instagram embed get example from insta
$http.get ("http://api.instagram.com/oembed?url=http://instagr.am/p/fA9uwTtkSN/")
.success(data) ->
$scope.html = data.html
...
the result in $scope.html contain a blockquote with many div and image
i've tested it in the view (with ngsanitize), but it show only the text and not the image.
Anyone have an idea about how to get it ? :D
thank you (sorry for my english).
You will have to use Angular's built in Strict Contextual Escaping $sce
$sce Documentation
Then, in your controller:
instaembed.controler "instaCtrl", ($scope, $http, $sce) ->
#instagram embed get example from insta
$http.get ("http://api.instagram.com/oembed?url=http://instagr.am/p/fA9uwTtkSN/")
.success(data) ->
$scope.html = $sce.trustAsHtml(data.html);
...
You need to use ngBindHtml directive.
https://docs.angularjs.org/api/ng/directive/ngBindHtml
<div ng-bind-html-unsafe="html"></div>
Where html is your $scope.html variable. This will render inside div what your variable contains.
function testCtrl($scope) {
$scope.html = "<strong>Hello world!</strong>"
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<div ng-controller="testCtrl" ng-app>
<div ng-bind-html-unsafe="html"></div>
</div>
You should use ng-bind-html
<span ng-bind-html="your scope variable"></span>
I am new to writing directives. I have this snippet of code that works and I am trying to make it a directive:
<div ng-click="details=!details" class="row toggleHeader" ng-class="{open : details}">
<div class="col-md-12">
<h4>Some title</h4>
</div>
</div>
<div id="the-details" class="row" ng-show="details">
<div class="col-md-2">
...content...
</div>
</div>
So, my initial pass was
app.directive('pbTogglePanel', function() {
return {
restrict: 'A',
scope: {
variableName: '#',
panelTitle: '#'
},
template: '<div ng-click="somevariable=!somevariable" class="row toggleHeader" ng-class="{open : somevariable}">\n<div class="col-md-12">\n<h4>{{panelTitle}}</h4>\n</div>\n</div>\n\n<div id="the-somevariable" class="row" ng-show="somevariable">\n<div class="col-md-2">\n...\n</div>\n</div>',
};
});
with the html
<div pb-toggle-panel panel-title="My Directive Panel Test" variable-name="foobar"></div>
This works, in the sense that the panel toggles as expected. I obviously did not try to use the variable "foobar" passed from the html attribute. When I try to use it, the code throws an error and the toggle does not work. I tried using the template:
'<div ng-click="{{variableName}}=!{{variableName}}" class="row toggleHeader" ng-class="{open : {{variableName}}}">\n<div class="col-md-12">\n<h4>{{panelTitle}}</h4>\n</div>\n</div>\n\n<div id="the-{{variableName}}" class="row" ng-show="{{variableName}}">\n<div class="col-md-2">\n...\n</div>\n</div>'
Although "foobar" shows up in all those places, the toggling fails and the console logs an angular error.
So, what's the correct way to pull in more than one html attribute?
Also, the goal would be to allow the contents of this DIV to replace ...content... placeholder in my template. Not sure how to pass that either.
I feel if I can just get my head around how this data is passed, I'll be good from there out.
TO HELP CLARIFY
This works: http://codepen.io/smlombardi/pen/MYygpy
But I wanted to pass the name of the variable for the toggler to use from an attribute too, and this does NOT work:
http://codepen.io/smlombardi/pen/KwzPaw
The problem of your last, non-working example is not about passing multiple parameters but rather abusing the angular's interpolation mechanism. If all you want is to use the variableName, the minimal change to make your last code example work (that is to collapse/expand) would be to change the template from string to function with concatenation:
{...
template: function(tElem, tAttr){return '<div ng-click="' + tAttr.variableName + '=!' + tAttr.variableName +...;
}
But there is no point to do so as long as you use directive isolating scope, which effectively hides the value of the variableName from you. You will also probably want to change to scope:false and get attributes from the tAttr of the template function instead. Modified example.
I am using the following way to use $scope variable ({{func}}() in this case) as function name in ng-click.
<button type="button" ng-click="{{func}}()">Call {{func}}</button></pre>
This works in angularjs-1.2.0rc3. See working plunkr here
Any future version from > 1.2.0rc3 throw this error
What's changed? How can I use the above syntax in current angular version?
Ok first of all I do not recommend such a usage for ng-click because angularjs itself do not support this, but if you still want to use it such a way here is your solution...
<button type="button" ng-click="$eval(functionName)()">...</button>
where
$scope.f1 = function() {
...
};
//name of function as a string
$scope.functionName = "f1";
this is what your are looking for and here is your PLUNKER example...
All I did was append scope to both variables
<form name="angular" ng-controller="Ctrl">
<button type="button" ng-click="{{scope.func}}()">
Call {{func}}
</button>
<label>Status: {{scope.status}}</label>
http://jsfiddle.net/bebold/TmKLY/1/
I wouldn't advise going this route for dynamic variable change, a better choice would be to create a directive and do the binding within the template:
A great explanation can be found HERE.