Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am working on an online html presentation editor that is currently in production.
Eventually, I would like to re-write it using angular, preferably by gradually replacing components of the app rather than rebuilding it from the ground up.
To Start, I would like to implement new features using angular.
In summary, the question is how to handle the case of an application where only certain sections are using the framework?
It seems that the angular app would need to interface with the rest of the app through an api, as if its an external entity.
EDIT for clarification:
the application resembles power-point with a stack of slide thumbnails. The selected slide contents are loaded into an editable work-space, where changes are applied via a menu to the selected element.
I would like to add an audio feature to the menu. It's a form that edits data attributes on the selected element. These data attributes are used to generate an html5 audio element elsewhere.
If I were to build the audio module using angular:
1.The ng-app attribute would have to be on a parent element of both the workspace and the menu.
input controls in the add/edit/remove audio form have to be bound to the same model as the selected element's data attributes.
example:
<input value="{{loop}}">
<div class="element selected" data-audio-loop="{{loop}}">
3.when opening the audio form the angular app needs to be aware of what the selected element is.
4.only this element needs to be bound to the same data as the form.
steps 3 and 4 are where I am not sure about the implementation.
If the entire app was modeled in angular, then step 3 would be easy, because there would be a model that tracks the selected element.
How should the angular module be made aware of what the selected element is, So that it can apply its bindings?
EDIT: (further clarification)
assume I have these elements, only one of which is selected:
<div class="element selected" data-loop="{{loop}}">
<div class="element" data-loop="{{loop}}">
<div class="element" data-loop="{{loop}}">
<div class="element" data-loop="{{loop}}">
and this input:
<input ng-binding="loop">
how can I make the binding only affect the selected element, and not all the elements?
There's no reason not to gradually introduce Angular in your app. If you're currently using JQuery, Angular will use it as well. In not, it will fall back on internal alternative jqlite.
As dabee says, only the code inside the directive ng-app is under control of angular, and you can put that tag on any compatible element (div, ul, etc.) it doesn't have to go on the body tag and control the whole page.
You could encapsulate the interaction with the rest of the app by wrapping data access in a service (a recommend practice in any case) - or through reading & writing to the DOM. In the event that you need to respond to changes in the DOM through actions outside of angular's control, you might want to check the ng-ScrollSpy directive's code for a potential method: An AngularJS module for navigation highlighting
Further reading: http://henriquat.re/directives/advanced-directives-combining-angular-with-existing-components-and-jquery/angularAndJquery.html
Responding to the most recent update:
To make the directive apply only when the class is selected, test for selected in the directive itself. See: How do I apply an AngularJS directive based on a class set by ng-class? In particular, you'll want to extend the function that adds the selected class - it should update a variable that's accessible to angularjs code whenever the element has been updated (or fire an event that you'll handle in the directive code). Create a $watch on that variable (or add an event handler), and apply the dom transformation to add or remove the feature as applicable.
Only the code inside the tag with directive ng-app is under control of angularJS. Thus the remaining code can be control by any other tool.
http://docs.angularjs.org/api/ng.directive:ngApp
Related
Some (advanced?) angular is making my head hurt.
The goal is to extend a WYSIWYG HTML editor to allow users to insert certain angular directives into arbitrary HTML content. I have chosen medium-editor and its angular-medium-editor wrapper (but I'm not wedded to that if there are better solutions).
This Plunk shows how the editor directive is instantiated and activated (using an editable attribute). The toolbar is customised to include a button which adds a custom directive around selected text: <my-custom-directive class="bg-info"> ... </my-custom-directive>. (For demonstration, the custom directive wraps (transcludes) its contents in a button which triggers an alert when clicked).
I'm having problems with (re-)compiling the editor's content so that the directives inside the editor compile. Using $compile(element.contents())(scope) throws ngTransclusion:orphan errors for directives which uses transclusion. (I understand this is due to angular already having made the transclusion by the time the editor's link function is called.)
I cannot refactor all potential custom directives to not use transclusion.
What pattern can I use to successfully compile arbitrary editor content (which may include many different directives), ideally whenever that content changes, or at least when the editing is finished? Is this one of the "fringe cases" where the use of $compile is justified? If so, how do I use it?
This question and answer made me realise that the way to do this is to $compile only the inserted element when it is inserted, rather than recompiling the whole section.
Handily, rangy's classApplier module allows for an onElementCreate callback which can be used to compile the custom directive as it is added.
Here's the working plunker.
I had an app that I got 80% through building a few weeks back and it uses a lot of jQuery to do animations. I stopped working on that and started rebuilding it from scratch using AngularJS.
I'm now at the point where I'd like to try to add some of the animations that I WAS using in the old app. When leaving from the "main page" to the "details page", I used to have one div go flying offscreen to the left, while the main table seemed to shrink upwards and sort of "merge with" a drop-down box that was coming into view for that new details page. (The table and the drop-down have essentially the same information, which is why the animation made sense. The drop-down allows them to jump from record to record, without having to go back to the main table to navigate.)
Anyways, the way I built this app in Angular is that it is working off of one index file with a single "ng-view" div in it. And then the router determines what template-page to pull in.
I see from the various tutorials out there on animating with AngularJS 1.2 that the "ng-view" fires off events that can be harnessed for animation. But that's ONLY if you're going to add your .css class to be animated to the div that holds the "ng-view".
<div class='whatever' ng-view>
and then your css would contain something like:
.whatever.ng-enter{
opacity: 0;
}
But what can I do if I want to animate the way various PIECES of a view template enter or leave the view? (Most are just divs that act as containers for small tables of data [ as divs, not tables].) I'm using "ng-repeat" in those templates to populate the tables, but I really don't want to animate any of the rows. That's about the only other directive that fires Angular's animation that I'm currently using in the templates.
You can set animations to different parts of your template in it's controller using Jquery itself.
myApp.controller('sampleController', function($scope, $timeout, $location){
$("#submit_button").click(function(){
$("#yourdiv").fadeOut();
$timeout(function() { $location.path('/newurl'); }, 3000);
});
});
Display all your animations then change the route. I have used $timeout so as to set a delay for displaying the animations.
I'm stuck with Angular. I have a directive that shows a list and when the user hovers over an item, I want to show a preview of the item, with the preview being given by the directive user.
Some tricks though... I want the user to be able to filter the list using an input [which is easy on it's own] and there is some basic styling surrounding the list that I would like the directive to handle, like adding the checkboxes that well be watched to create the model for the directive.
I want the directive user to simply be able to write:
<preview-list list='unfilteredlist'>
<div>
<h1><blink>{{title}}</blink></h1>
<h2><marquee>{{html extrodinaire}}</marquee></h2>
</div>
</preview-list>
I tried using ng-transclude, but it uses a sibling scope and I've been looking for work arounds and I can't find any. The only ones I found involved writing the entire template in javascript, which honestly I can't believe people think that's an acceptable solution.
Any solutions, or is this actually completely impossible in Angular?
As i see it you have two options :
Create a preview box for each member in your list and toggle visibility on hover. This is great if you have only a few values and the preview box is heavy.
Create a transcluded directive in which - the main scope will hold the list and the currently hover element. The sibling scope will hold the preview container. Once the selected value changes the preview box will update (according to your bindings) and only thing left to do is position it.
transclude is hard at first but it pays off.
Hope this helps.
I'm in need of some pointers in my landingPage-builder project. (i'm currently stuck!).
The main issue is as follows:
Each element in the template (like the h1 and the paragraph) has attached a directive. What I need to get the directive to do is: create a template of HTML with some other directives attached like ng-click, ng-options etc, keep the bindings to the model intact (currently far away from working), update the model when changed.
I'm not trying to append to, or replace the element the directive is on, but make a html-template and inserting it into the DOM (almost like another view) so that the model on the left can be updated from the "settings" box on the right.
The project can be viewed here: http://193.107.29.196/~stian123/landingPageV3/app/#/pagebuilder/2
You may need Allow-Control-Allow-Origin for Chrome: https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi/related
I'm a bit confused about $compile and doesn't really know when I need to use this part of the directives api.
Any suggestions?
Thank you!
If I understood your question correctly, you want to dynamically create templates, some of which have Angular attributes in them, then attach them to the DOM.
First, to (hopefully) answer your question, about when to call $compile:
Whenever you load in HTML from outside Angular's template system (like trying to set $(element).html(myHtmlString)), you need to let Angular compile it before you attach it to the DOM. In other words:
elem.append($compile(yourHTMLString)(scope));
This lets Angular traverse the DOM and parse any directives and bindings and attach them to the provided scope. If you don't $compile, Angular has no idea about those intended bindings at all, the HTML is never read by Angular.
Second, I don't know how flexible you want your templates to be, but if they're relatively fixed, but with some fixed customizable options (text, color, font-size etc), you might be better off creating a directive for each 'view', with the view options bound to the scope of the directive. Then you can just change the fields on the scope of the directive in the panel on the right side, and the view will update directly. You wouldn't even have to use $compile in this case.
If you want the user to be able to manually add the template HTML code, you will have to compile the HTML as described above.
I need to build a dialog to be used with any item on a list of items. The dialog is pretty much the same regardless of the item except for the values of the fields which are obviously item dependent.
The directive I am building is reading the template from a file, compiles it with $compile and then binds (links) it to the scope of the item. The result of the binding is a DOM tree. To make the dialog visible I need to append this tree to some element in the existing DOM. The nature of my dialog is such that it makes sense to append it directly to the body tag. The dialog will be used many times in combination with different items on the list
So here is my question: How much of this process (compile, bind, append) can be done in advance? I certainly can run compile once. I can also bind the compilation result to the $rootscope and append (hidden) it to the body tag. This way I can later just turn on visibility and show the dialog.
But if it is already bound and attached to DOM, is it kosher to re-bind it to some other scope, if so - what's the right way to do it? Another question is is it even worth it? might be just re-insert it every time it is needed?
If you're only ever going to display one dialog like that at a time and you will use it frequently, you don't have to re-bind it to another scope, just change the data on the scope. Something like this:
Create a service for your dialog
Create the directive and inject your service into it. When the linking function executes, pass something like $scope.dialogData to the service so that the service can update the data.
Create a controller that gets the service injected. Set the dialog data through the service to display the dialog. Since you're modifying data in your controller that's on the directives scope, Angular notices that and updates your dialog.
Add ng-show on your dialogs wrapper to make it simple to implement open()/close() methods on your service.
Now you have a dialog that can be used from anywhere in your system, and you're just re-using the same directive without having to mess with the DOM or compilation.
This is indeed excellent question and I'm happy to see that more and more people are starting to approach dialogs as services.
Regarding your particular questions, here are some of my thoughts:
You can "cache" linking function (that is - function that is returned from the $compile call) and then call this function as needed (passing in scope variables).
Instead of inserting (hidden) compiled element you could only attach it on demand, when a dialog gets opened. On top of this I would rather attach modal element to the $rootElement instead of <body> just not to touch DOM elements above where ng-app was defined. Just not to touch parts of the DOM that AngularJS is not controlling.
IMO dialogs are really close to AngularJS routes (as they provide different "views") and as such it would be very nice to have ability to resolve promises before modal is shown (as with routes).
In fact there are number of things to consider when designing a good, generic dialog service and I hope that those advice, alongside with excellent input provided by others, will get you started. But this all is a bit theoretical so if you are looking at the implementation of what was discussed here you can have a look at this implementation. ($dialog service from http://angular-ui.github.com/bootstrap/ - it is fully customizable so can be used with CSS other than Bootstrap's. Documentation here).
It can be seen in action in this plunk: http://plnkr.co/edit/PG0iHG?p=preview
Excellent question I think. You're wondering if one can "hot swap" the scope of an element. I don't know if there's a way to do that, or even if there is, if that's the Angular way. I take it you looked at how ng-view works to get as far as you've gotten?
My advice is to do the $compile once, keep the result, the link or transclusion function or whatever it's called in Angular parlance, around somewhere. And call it for each needed instance of the dialog.