I have jsonData which consist of HTML content. I want to render that HTML in ng-grid. The content is not rendered however -- it only shows up in normal string format.
Below is the plnkr which shows all the code:
http://plnkr.co/edit/RlWyDqCUUR15dmLM7ePV?p=preview
There's a few things going on here:
Not related to your exact issue, but you've got nested single quotes in your firstName field. You need to do some escaping or your ng-click expression is going to break. So instead of ng-click='show('F:/cox/main.html')' you can do ng-click=\"show('F:/cox/main.html')\".
Also not related to your exact issue, but if you want to access properties on your controller's scope from inside UI-Grid you need to use appScope. The docs on it are here: http://ui-grid.info/docs/#/tutorial/305_appScope
The main problem with getting HTML provided from inside your app to render is Strict Contextual Escaping.
Strict Contextual Escaping (SCE) is enabled by default in Angular and escapes any arbitrary HTML to prevent things like XSS and clickjacking. In order to get your HTML to show up you need to trust it, and bind it with an HTML bind expression.
You can use the $sce service to trust the HTML. Just iterate over your rows and do $sce.trustAsHtml(row.firstName). (You can read more about SCE here: https://docs.angularjs.org/api/ng/service/$sce) Then you will need a custom cell template to bind the HTML. The simplest one looks like this:
<div class="ui-grid-cell-contents" ng-bind-html="COL_FIELD"></div>
COL_FIELD will get transformed by UI-Grid into the proper binding for your field. Now the problem is that your ng-click directive doesn't get compiled. You need to use a directive that will take your custom HTML and compile it. You could roll your own, or use something like this library to do it for you: https://github.com/incuna/angular-bind-html-compile
The main thing to keep in mind is being able to actually trust the source of your HTML. If you can't be sure then going about this another way (i.e. by not providing HTML inside your data set) would be better.
I've modified your plunker to show all this working together: http://plnkr.co/edit/MgLoeGBoRTi2fF3e6pia?p=preview
Related
My goal is to produce an HTML string that will be saved in a database and can be displayed in other angular apps.
I was able to get that string but any ng-repeats and ng-includes are still a part of that markup so when I try to display that HTML it essentially tries to compile it again and since there are no values within the ng-repeat or ng-bind it ends up not showing those pieces.
The markup is pretty much perfect if I can just get rid the ng-binding and ng-repeats, or possibly tell Angular to ignore the ng-repeats/ng-includes on the side I'm displaying them. Any ideas?
You can clean it by appending the html into a temporary element. Then manipulate those elements removing classes and attributes. When done return the innerHTML
var $el = angular.element('<div>').append(yourHtmlString);
$el.find($el[0].querySelectorAll('[ng-repeat]').removeAttr('ng-repeat');
var result= $el.html();// raw non angular html
This is a bit oversimplified since you may also need to remove comments that angular uses as placeholders so is provided as concept only
I use pre tags extensively to debug my code in angular js, like so:
<pre>{{vm.names | json}}</pre>
Two questions:
how does this work under the hood?
is there an equivalent tool
with reactjs that lets you see variables' values in the view, instead
of the more common console.logs/debuggers?
You can add <pre>{JSON.stringify(this.state.data, null, 4)}</pre> to the Component holding state to "visualize" the data in your view.
Your <pre> tags have nothing to do with debugging -- they are just HTML elements.
To break down what's happening in your HTML markup snippet:
` does some HTML formatting.
Double Curly Braces {{}} indicate
data binding. (Two-way, to be honest).
vm.names is an object for that
Controller (Without a fiddle, etc, I can't lay out the rest of the
way it's instantiated)
| json tells angular to filter vm.names
using the json
filter.
It looks as if React uses the DOM and a .render function. Have a look at their Getting Started page.
For how this works under the hood, you may want to read about ng-model and how it works, and also Understanding Angular's $apply() and $digest() to get a handle on angularjs model binding.
EX:testDirective
I have one directive(testDirective) have some of the fields implemented like
Text,Textarea,select,checkbox,radio buttons.Here I want to use this implemented directive in some other view page like html page by placing inside div tags
ex:<div test-directive></div>
what I have doubt is I dont want to use all fields which is available inside directive.I need only Textarea alone so how can i use please give me example for this.
I'm very(!) new to Angular.js and am trying to understand where to put the various parts of my logic in order to follow best practices and separate business and presentation logic.
My specific use case is that I have a list of courses with a number of signups and a number of available seats. Based on these values I want to present a progress bar (or, if the available seats is not set, just a text).
My question is where to put the various parts of the logic, and how to pass the values along properly. So far I've created the HTML-part of a directive, like so:
<signupprogress available="{{course.available_seats}}" filled="{{course.filled_seats}}"></signupprogress>
My question is then (first and foremost) if a directive is the proper way to do this and, of so, if the logic for constructing the progress bar should go in the compile function, link function, in a template, or some other place. To me the compile of link function seems to be most correct, but I don't want to fill them with HTML, nor am I able to properly get the attribute values from the HTML (the attrs.$observe examples I've seen only implement the getting of one attribute).
Yes, use a directive since you need to modify the DOM.
If all of the HTML for the progress bar and the alternative text can be placed in the directive's template, then do that. And, if that is possible, use '#' for one-way binding, which makes it clear that the directive does not need to modify the "available" and "filled" values. If you find you need a linking function, then as #ShaiRez mentioned, '=' is probably easier. (BTW, here is a way to $watch multiple attributes, instead of using $observe. Maybe the same technique can be used for $observe.)
To display either a progress bar or the alternative text in the template, use ng-hide or ng-show in the template. Here's a simple example of that (which also uses '#').
The directive is the way to go in my opinion.
I would have my HTML content inside of a template, the logic inside of the link function (the compile function is usually more for repeaters etc).
And use the "scope" property in the directive definition, set to "=", that way changes are reflected automatically.
I have the following line in my html:
<div ng-bind-html-unsafe="departmentConfig" class="control-group"></div>
and I use a $resource get to retrieve the HTML, assign the HTML to $scope.departmentConfig, and then the view is updated perfectly. The HTML that is assigned to $scope.departmentConfig contains form elements, with ng-model attributes in it, but when I change the values in these input elements, they don't update the $scope model at all.
This is what I have tried, based on a lot of other internet posts, and it isn't working:
$resource('resources/sources/departments/:mappedName', {
mappedName:departmentKey
}).get(function(departmentConfig) {
// This will call another function that will build a chunk of HTML
$scope.departmentConfig = $scope.buildDepartmentConfigHtml(departmentConfig);
// This is my feeble attempt to access the element, and bootstrap it to include the items in the $scope model.
var $departmentConfigContainer = $('#departmentConfig');
angular.bootstrap($departmentConfigContainer, ['sourcemanager']);
I have even seen some jsFiddle examples where this appears to be working, but mine isn't. Am I calling bootstrap too soon? I also tried putting a $watch on $scope.departmentConfig like this:
$scope.$watch('departmentConfig', function() {
var $departmentConfigContainer = $('#departmentConfig');
angular.bootstrap($departmentConfigContainer);
});
but it didn't work either. I bet there is an easy explanation to this, I just can't seem to get the input elements with ng-model that are loaded after page compile to get bound to the model. Any help is appreciated, this is the last piece of functionality I need to get working on my page. Let me know if you need more information about my configuration as well.
So, simply put, how can I force a section of the DOM to recompile after I know it has been loaded?
UPDATE
Here is a jsfiddle outlining what I would like to do: http://jsfiddle.net/j_snyder/ctyfg/. You will notice that property two and three don't update the model, and I am calling bootstrap on the outer div, hoping that will include those in the model binding. This is the first time I have posted to jsfiddle, please let me know if you can't see the example.
ng-bind-html is made for regular HTML, not compiling new angular elements.
You will have use the $compile service.
Here is how you would edit your current example to work: http://jsfiddle.net/andytjoslin/ctyfg/21/. But this way ends up being bad, because you have to do DOM manipulation in your controller.
You just need to create a directive that will basically do what you wanted ng-bind-html to do: http://jsfiddle.net/andytjoslin/ctyfg/22/