Using Angular Bootstrap directive "uib-popover" with dynamically generated SVG content - angularjs

I have a case where I am dynamically generating SVG. This is in various forms but, for example, I do things like this;
<rect uib-popover=\"I will show data!\" popover-append-to-body=\"true\" popover-placement=\"bottom\" popover-trigger=\"mouseenter\" id=\"component-#{SecureRandom.uuid}\" x=\"#{pos_x + (component_width / 2)}\" y=\"#{MID_LINE - (component_height / 2)}\" width=\"#{component_width}\" height=\"#{component_height}\" style=\"stroke-width:0.5; stroke:rgb(0,0,0)\" />
The SVG document is sent back to the browser and dynamically injected into a DIV (via an Angular controller).
The problem is that the popover will not appear. It seems as if the page is not "re-scanned" when the content is injected (and therefore the uib-popover is never seen).
I have done some tests to confirm this. For example, a direct placement of SVG in the page works;
<svg>
<circle cx="30" cy="30" r="10" uib-popover="Hello world" popover-title="Title!" popover-append-to-body="true" popover-placement="right" popover-trigger="mouseenter"/>
</svg>
And the popover is displayed.
Doing it this way though, does not work;
<div ng-bind-html="svg"></div>
Where the svg variable is within the controller and is set by;
$scope.svg = $sce.trustAsHtml('<svg><circle cx="30" cy="30" r="10" uib-popover="Hello world" popover-title="Title!" popover-append-to-body="true" popover-placement="right" popover-trigger="mouseenter"/></svg>')
In this case the popover does not appear.
So what am I missing? Is there any method by which I can inject SVG dynamically into a page and have the Angular/Bootstrap directives work? Perhaps some way to tell the directives to re-bind?
Cheers,
Ben

Related

Why does an un-rendered element behave as if it has been rendered?

I am slightly confused by this behaviour of Angular JS.
Angular.js' ng-if will not render an element if the expression evaluates to false, if the documents are anything to go by. I have this piece of code in my html template:
<div ng-if="false">
<img src="{{ imgPath }}" />
<p>This block is not rendered</p>
</div>
// In the controller
$scope.imgPath = "/invalid/image/path";
When this template is rendered, I cannot, as expected, see the img element or the p element on developer tools:
However... when I look at the network tab, there is a request to fetch the image:
I thought that if the element is not rendered, it wouldn't function in any way or form since it doesn't exist... Why does the browser fetch the image in this case?
You can see the working code on plnkr here, you'll have to hit F12 to watch the error on the console.
I know that using ng-src= {{ }} instead of src={{ }} would solve the issue of img src being fetched with unresolved expression before the data is bound, but, this question deals more with why ng-if isn't stopping the request in the first place
It takes AngularJS a small amount of time to process your markup. So, intially when your page loads, the browser does it's thing trying to process the markup. It sees this:
<div ng-if="false">
<img src="{{ imgPath }}" />
<p>This block is not rendered</p>
</div>
But, so far, AngularJS has not been loaded, and the AngularJS directives have no meaning. The browser attempts to load an image located at the literal URL of : {{ imgPath }}, which the URL encoder will translate to %7B%7B%20imgPath%20%7B%7B, which will fail (obviously). Still, AngularJS has not been loaded.
Once AngularJS finally loads, it goes through the DOM and applies the ngIf directive and removes the node.
This is why you want to use ngSrc. This will prevent the image request, since the browser doesn't understand the ng-src directive and won't treat it like a src attribute.

How to put bootstrap tooltip over SVG elements in angularjs

I want try to put bootstrap tooltip over svg element in angularjs, I am not using d3.js, I simply using angularjs. If you give explanation with example that would be preferable.
The trick is just to append it to the body instead of the parent element.
I created here an example with UI Bootstrap angular directives.
<svg>
<circle cx="60" cy="60" r="50" tooltip="Hello world"
tooltip-append-to-body="true" tooltip-placement="right"/>
</svg>
As AngularJS is deprecated, this is how is done in Angular using ng-bootstrap:
<svg>
<circle cx="60" cy="60" r="50" tooltip="Hello world" container="body" placement="right"/>
</svg>
Reference

Best approach to change background image in AngularJs at runtime

I want to create generic feature that allows me to change background image of any section. After going through options provided I found these two approaches. Want to choose best approach to change image because on single page I want multiple times change background facility. It will be available to four to five sections.
Approach
Using Directive check this stack overflow link.
Also there is another approach of angular scope variables that we can updates at runtime.
<div ng-style="{'background-image': 'url(/images/' + backgroundImageUrl + ')'}"></div>
Required Usage ( With respect of Directive )
<body>
<section backgroundImage url="{{backgroundImageUrl1}}">
...
</section>
<section backgroundImage url="{{backgroundImageUrl2}}">
...
</section>
<section backgroundImage url="{{backgroundImageUrl3}}">
...
</section>
<section backgroundImage url="{{backgroundImageUrl4}}">
...
</section>
</body>
As shown above I am going to update background-image attribute for each section. If these property is set inside CSS file, it will reduce time to load images i.e. If we directly add inline css styling in HTML, all images will loaded on DOM load. It will make extra request to server to get images and load them in DOM. I wanted to follow strategy that will reduce loading time in my SPA(Single Page Application).
I think going with <div ng-style="{'background-image': 'url(/images/' + backgroundImageUrl + ')'}"></div> should be more effective.
You dont introduce another layer of complexity, directives create scopes, which are watched and digested, also directives must be compiled in the begining.
Using symple ng-style together with some specific url from controllers property shoudl only do request for that particular active image. Because of that i think it should be the optimal solution.

How can I open a modal from a modal template?

I'm new on Angular JS + Bootstrap 3 and I'm trying to do something for maps. the thing is that I need to open a modal, and then from a button of that modal open another modal.
This is the external html:
<div class="modal-header">
<h1>Editor<h1>
</div>
<div class="modal-body" >
<button class="btn btn-primary" ng-click="treureModalEdit()" data-dismiss="modal">Afegir Punt</button>
</div>`
Here is my example: http://plnkr.co/edit/Zx68EQ?p=info
If something does not load is because libraries, but i only need help where the button 'Posa Marcador!' is.
Some code is in catalan, sorry if that discourages you to help me.
Thank you!
If you inspect with your browser's developer tools the first modal that you open you will see that the markup for this modal is appended to the end of your HTML body, which means that the modal is not nested in your <div ng-controller="DialogDemoCtrl">. This in turn means that the modal does not have a controller of its own, and therefore cannot "understand" the ng-click="treureModalEdit()" you have defined for your button.
In order to fix this problem you should create a second controller and use it for your modal. The treureModalEdit() would then be placed into that second controller.
A few other comments I have on your code:
You use things like data-toggle="modal" data-target="#modalEdit", however this is how you would be opening your modal if you did not have an Angular application. In your Angular application what you actually use is the ng-click="func()" you have put on the button. You can therefore clean all this dead code from your HTML (data attributes and modal template).
If you are new to Angular I would suggest using a newer version in order to avoid any problems which might be fixed in newer versions. You can use the latest version (1.4.0) or a 1.2.x version is you need to support IE8 (which is not officially supported since Angular version 1.3.x.

How to click a particular tab using Angular and how to include Angular UI in the code

I am using Angular UI Bootstrap http://angular-ui.github.io/bootstrap/. I have two questions:
I followed the example given at angular-ui.github.io, there they use
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js">
but I don't want to use the CDN so I downloaded Angular UI and added it to my project. How to include it into my code?
I did add
['ui.bootstrap'] to my angular.module, but it's not working until I add the above script code.
I'm using <tabset> to create two tabs, contacts and group. For
example, a user is in the Group tab, he wants to add members to an existing group, so if he clicks the Add Member button, I want to navigate to the Contacts tab automatically.
I thought of using document.getElementByTagName() inside my
controller. Will it work? And what is the Angular way to click
something programmatically.
Question #1:
<script src="folder_of_js/ui-bootstrap-tpls-0.10.0.js"></script>
Question #2:
You don't use document.getElementByTagName() with AngularJS, if you want to navigate to a tab while you are in another tab's content, an example might be the following:
<tabset>
<tab ng-repeat="tab in tabs" heading="{{tab.title}}">
{{tab.content}}
<button class="btn btn-default btn-sm" ng-click="tabs[2].active = true">Select third tab</button>
</tab>
</tabset>
As you can also see in this plunker, I added a button that navigates to the third tab whenever you click it.
The script file is probably not loaded by the browser. You have to add a script tag pointing to where the file is in your project. For example, if the script is placed in the folder /scripts/lib/:
<script src="/scripts/lib/ui-bootstrap-tpls-0.10.0.js" />
One of the golder rules of AngularJS is to never, for any reason, referrence the DOM (i.e. an HTML element) from a controller. So while document.getElementByTagName() will technically work, I would advice against it.
In angular, you really don't click things programmatically. The common way is to bind something in your HTML to a variable in the $scope, either by curly brackets ({{someVariable}}), or by directives such as ng-class, ng-bind etc. Then you change that variable in $scope, and the HTML changes to reflect that. Is there a variable in $scope which determines which tab is open? If so, you can just change that variable, and it should work automagically.

Resources