Is it possible to dynamically add an ng-include element to a HTML page and have it actioned?
I have a Drag N Drop application where you can drag an element onto the page and in the drop zone the element is replaced with a more detailed element. For examples you drag a box that says Calendar and when it is dropped a calendar is presented. To be clear a new Element is created and added to the DOM, it does not exist before the drop.
When the element is dropped, I'm hoping that I can replace it with a chunk of HTML that looks like below. Instead of having the markup defined in a string like it is at the moment which is not very nice:
<div class='panel panel-default'>
<div class='panel-heading'>
<h3 class='panel-title'>
<span class='glyphicon glyphicon-remove'></span>
WIDGET NAME
<spanclass='glyphicon glyphicon-cog'></span>
</h3>
</div>
<div class='widgetContainer' ng-include="'widgets/widget.html'"></div>
</div>
When the above HTML is inserted into the page the referenced HTML file is not included.
What I would like to happen is a HTML file is loaded containing the widget markup and included at the appropriate position.
I'm new to Angular so I don't know if this is because:
dynamically adding ng-include isn't supported
whether I need to do something with the controller to handle this logic
should I be using the tag instead of the attribute?
it just isn't possible.
Please provide examples with solutions, as I said I'm new to Angular.
Thanks
UPDATE
The code used to created the HTML that I want to dynamically add to the page looks like this
$("#template").append(
" \
<div class='panel panel-default'>\
<div class='panel-heading'>\
<h3 class='panel-title'>\
<span style='padding-right: 10px; cursor:pointer;' class='glyphicon glyphicon-remove' onclick='removeElement(this)'></span>\
" + widgetDetail['serviceName'] + "\
<span style='float:right; cursor:pointer;' class='glyphicon glyphicon-cog' onclick='toggleWidgetDetail(this)'></span>\
</h3>\
</div>\
<div class='markupContainer' ng-include=\"'widgets/" + id +".html'\"></div>\
</div>\
"
);
I've uploaded the complete code to GitHub. The drag and drop aspects are being handled currently by HTML5 javascript, which can be seen in the file /public/javascripts/js_dragndrop.js. The new widget being added to the page (the code above) is in /public/javascripts/jq_dragndrop.js
I'm in the prototyping phase trying to work out the DragNDrop elements so don't expect high quality code :)
I found a way of achieving what I wanted by moving the HTML5 drop and drop code into AngularJS directives and then (using this [ Compile dynamic template from outside of angular ] as a guide) got the html templates being loaded where I wanted them.
The main code change looks like this:
angular.element(document).injector().invoke(function ($compile) {
var widgetDetail = widgets[e.dataTransfer.getData('Text')];
var obj = $("#template");
var scope = obj.scope();
obj.append(
"<div class='panel panel-default'><div class='panel-heading'><h3 class='panel-title'>\
<span style='padding-right: 10px; cursor:pointer;' class='glyphicon glyphicon-remove' onclick='removeWidget(this)'></span>\
" + widgetDetail['serviceName'] + "\
<span style='float:right; cursor:pointer;' class='glyphicon glyphicon-cog' onclick='toggleWidgetDetail(this)'></span>\
</h3></div><div class='markupContainer' ng-include=\"'widgets/" + widgetDetail['serviceId'] + ".html'\"></div>\
"
);
$compile(obj.contents())(scope);
scope.$digest();
});
You can find the full code in the Git Project /public/controllers/template.js if you are interested.
Related
I want to know the best way to proceed given the following information:
I have a controller which makes 2 http calls using a factory.
DataFactory.getTestDisplaySections(testID).then(function (response) {
$scope.testSections = JSON.parse(response.data);
});
DataFactory.getTestObjectByTestID(testID).then(function (response) {
$scope.testObject = JSON.parse(response.data);
});
The call returns two arrays. I want to generate html with data from the array embedded in it. Right now, my template for the controller contains only an empty shell of a page.
<div class="container">
<div class="row">
<div ng-bind-html="sectionHTML"></div>
</div>
</div>
The sectionHTML above is my variable which contains the html markup for the entire page.
The first call returns data that gives me names of panels that are to be displayed on the page. These could be 4 or more. I want to use the following html to display each panel.
$scope.sectionHTML = '<div class="col-lg-6">'+
'<div class="panel panel-primary">'+
'<div class="panel-heading lead">' + panelDiaplayName + '</div>' +
'<div class="panel-body">'+
'<div id="test_info" class="col-lg-12">' +
'</div>'+
'</div>'+
'</div>'+
'</div>'
Should I just go through the panel data in a for loop and create the html that way for each panel?
When I try to add the panelDisplayName using {{}} It shows up as just {{panelDisplayName}} will this be an issue, every time I have to evaluate an angular expression? How can I resolve this issue?
Second, I have other information that I need to display within each of the panels. This comes from the second http call. Each panel will have details in it and each piece of information will be editable. Can anybody help with the best way to do it?
I can give more explanation if anyone needs it.
Thanks
Paras
I think you are asking about multiple issues here, so I will try to help solve the first two, looping through your array to build your page and helping you get the {{}} data-binding to work.
For your panels, don't use a for loop and build html in your controller. You are using angular, the angular way is using ng-repeat. You add this to your html template and it will build the dom by iterating over your array. In your example:
.html
<div class="container">
<div class="row">
<!-- this is where we are iterating over the array (ng-repeat) -->
<div class="col-lg-6" ng-repeat="section in testSections">
<div class="panel panel-primary">
<!-- section is the current item being iterated in the array, so we are printing the displayName for the section -->
<div class="panel-heading lead">{{section.panelDiaplayName}}</div>
<div class="panel-body">
<div id="test_info" class="col-lg-12">
</div>
</div>
</div>
</div>
</div>
</div>
As for the data-binding. My assumption here is that you aren't adding ng-app and/or ng-controller to elements that encompass your data-bindings. For example:
.html
<body ng-app="yourApp" ng-controller="yourController">
<h1>{{testMessage}}</h1>
</body>
app.js
var app = angular.module('yourApp').controller('yourController', ['$scope', function($scope) {
$scope.testMessage = "Hello World";
}])
As for your second question about dealing with data that will be edited, I recommend giving that a shot yourself. Look in to angular forms and ng-model. Those should help you get started. After giving that a shot, if you are still struggling, ask a new question for the specific issue you are struggling with.
I'm creating tabs dynamically in bootstrap tabs using jQuery. This is triggered with an event
To more clear look here is what I'm doing:
$('.tab-content').append('<div class="tab-pane" id="tab_' + id + '"> </div>');
Now inside the <div> I'm going to write a long HTML so I thought that it could be messy if I write all the code in the jQuery. So I decided to make an external file and import it using JSTL and write the import inside the jQuery code:
$('.tab-content').append('<div class="tab-pane" id="tab_' + id + '"> <c:import url="flt-pis.html"></c:import> </div>');
The <c:import url="flt-pis.html"></c:import> of JSTL seems not working, I don't know why. Is there an other way around?
jstl is run server side. javascript client. This won't work.
You can reference jstl inside embedded javascript with in your jsp page- the text is output to the js on server side.
Like mentioned before you cannot run JSTL on client side.
Given that the page is on the same domain (and by the sound of it, it is) you can use jQuery "load" function to put HTML from external file in your newly created div.
for example, after you execute this
$('.tab-content').append('<div class="tab-pane" id="tab_' + id + '"> </div>');
you can then do this:
$("#tab_"+id).load("flt-pis.html");
I have a Parse.com backend and am rendering its data, ultimately, with a jQuery append, like this:
$(".albums").append(
"<div class='col-xs-6 col-6 col-sm-3 col-lg-3'><div class='flip animated fadeInDown' style='-webkit-animation-delay:" + i * 0.1 + "s'><div class='card'><div class='album front' style='background-image:url(" + bigImg + ")'><img class='artwork' src='" + artwork + "' alt='" + collectionName + "' /></div><div class='album back' style='background-image:url(" + back + ")'><img class='artwork' src='" + back + "' alt='" + collectionName + "' /></div></div></div></div>");
It's a for loop hence the need for the various HTML elements and their classes. I know it's an appalling, shameful way to do it (and I believe it's causing a memory leak).
My questions are: How can I remove as much of the HTML from this append statement as possible? Should I be using a templating language?
If you think you might want to use a templating language you can start by building your own, super simple, template.
Simply replace
"some string stuff " + someValue + " some more stuff"
// instead
var myTemplate = "some string stuff {someValue} some more stuff";
// now render
myTemplate.replace('{someValue}', someValue);
It's easy to go further, and wrap this in a function to "render" that takes an object as an argument and iterates over keys. Done carefully this will provide you a subset of the functionality provided by "off-the-shelf" templating libraries so you can always cut-over later.
This will allow you to predefine your "template" and render using the data input provided. The next question is where do you want to define your template. Generally you would relocate it to a separate free-standing file that the designers would have access to, perhaps in a "templates" directory. But then you have to load it.
If you have lots of templates, some libraries would allow you to pack them together in one file, load the file, then ask the library for a specific template by name. Your designers would then control this file and the CSS that goes with it. If you have a lot of this, then the architectural overhead starts to make sense.
Whether you want to go down that road really depends on your specific circumstances and the structure of your project team.
I like Handlebar for this sort of thing.
This would be the template
<script id="albumsTemplate" type="text/x-handlebars-template">
<div class='col-xs-6 col-6 col-sm-3 col-lg-3'>
<div class='flip animated fadeInDown' style='-webkit-animation-delay:{{delay}}s'>
<div class='card'>
<div class='album front' style='background-image:url({{bigImg}})'>
<img class='artwork' src='" + artwork + "' alt='{{collectionName}}' />
</div>
<div class='album back' style='background-image:url({{back}})'>
<img class='artwork' src='" + back + "' alt='{{collectionName}}' />
</div>
</div>
</div>
</div>
</script>
And then you would use it like this:
var source = $("#albumsTemplate").html();
var template = Handlebars.compile(source);
var html = template({delay:i*0.1,
bigImg:bigImg,
collectionName:collectionName,
back:back});
$(".albums").append(html)
Adding html() to the call should do it. That'll return the html inside of .albums. To get everything including .albums you do $('.albums').append(...).parent().html().
How can I set datas with CKEditor (4.0) with CSS style ?
$quote = $editor + '<br />'+
'<div class="quote">'+
'<div class="quote-infos">'+
'<i class="icon-comment icon-white"></i>'+
' <span class="quote-user">'+$user+'</span>,'+
' <span class="quote-date">'+$date+'</span> :'+
'</div>'+
'<blockquote>'+$div.html()+'</blockquote>'+
'</div>';
editorMessage.setData($quote);
In this code, when I send the datas to a POST form, I just have <div><div><i></i><span...
If you are using the new 4.1 CKEditor, it might be because of the new Advanced Content Filter feature. It nukes tags, attributes and attribute contents from content HTML, see demo. Turn it off by adding config.allowedContent = true to your config. More info on configuration in the API
You can test for this easily in your CKE instance by going to source mode, adding some attributes manually into the content, like <div class="MagicalPonies"><div><i></i><span... Then switch to wysiwyg mode and back to source mode. If your class definition is missing, it's most likely ACF. Also try to add a class like <img alt="X" class="left" src="http://b.cksource.com/a/1/img/sample.jpg" /> and see if that sticks. Standard CKE classes like that aren't removed.
I have several templates for faceboxes (lightbox) that I need at different points of the application. These are stored in different partials and files.
I will initialize different javascript functions in accordance to which ones I need. The question is, what is the best way to append the external HTML page into my body using javascript?
Since you tagged the question with it, here's a jQuery solution.
$("body").append("text");
Remember that the parameter can also be a DOM element. So you can do this :
var p = $("<p/>").text("a paragraph");
$("body").append(p);
the easy way with jQuery is:
$('#result').load('test.html');
<div id="result"><!--/ Hold My Data! /--></div>
obviously you can change #result with body
Also you can try some templates library..
Like handlebar and underscore..
and append in the el provided by backbone.js
Suppose you want to append this html in your template, then you can use the below code according to your application
Consider the code
Example 1:
rowData += '<div style="width: 130px;">'+param1+'</div>';
rowData += '<div style="width: 130px;">'+param2+'</div>';
$('#ID').html(rowData);
and please make sure that the js should be include in that file.
Here is the information of variable used above:
row data - the html that you want to append,
param- if you want to show the value of java script variable on browser dynamically,
#ID- ID of the div in which you want to append this html
example 2:
Consider the following HTML:
<h2>Hello World</h2>
<div class="user">
<div class="inner">Hi</div>
<div class="inner">Bye</div>
</div>
You can create content and insert it into several elements at once:
$( ".inner" ).append( "<p>Lorem Ipsum</p>" );