I have this AngularJS app. Everything works just fine.
Now I need to show different pop-ups when specific conditions become true, and I was wondering what would be the best way to proceed.
Currently I’m evaluating two options, but I’m absolutely open to other options.
Option 1
I could create the new HTML element for the pop-up, and append to the DOM directly from the controller.
This will break the MVC design pattern. I’m not happy with this solution.
Option 2
I could always insert the code for all the pop-ups in the static HTML file. Then, using ngShow, I can hide / show only the correct pop-up.
This option is not really scalable.
So I’m pretty sure there has to be a better way to achieve what I want.
Based on my experience with AngularJS modals so far I believe that the most elegant approach is a dedicated service to which we can provide a partial (HTML) template to be displayed in a modal.
When we think about it modals are kind of AngularJS routes but just displayed in modal popup.
The AngularUI bootstrap project (http://angular-ui.github.com/bootstrap/) has an excellent $modal service (used to be called $dialog prior to version 0.6.0) that is an implementation of a service to display partial's content as a modal popup.
It's funny because I'm learning Angular myself and was watching some video's from their channel on Youtube.
The speaker mentions your exact problem in this video https://www.youtube.com/watch?v=ZhfUv0spHCY#t=1681 around the 28:30 minute mark.
It comes down to placing that particular piece of code in a service rather then a controller.
My guess would be to inject new popup elements into the DOM and handle them separate instead of showing and hiding the same element. This way you can have multiple popups.
The whole video is very interesting to watch as well :-)
Create a 'popup' directive and apply it to the container of the popup content
In the directive, wrap the content in a absolute position div along with the mask div below it.
It is OK to move the 2 divs in the DOM tree as needed from within the directive. Any UI code is OK in the directives, including the code to position the popup in center of screen.
Create and bind a boolean flag to controller. This flag will control visibility.
Create scope variables that bond to OK / Cancel functions etc.
Editing to add a high level example (non functional)
<div id='popup1-content' popup='showPopup1'>
....
....
</div>
<div id='popup2-content' popup='showPopup2'>
....
....
</div>
.directive('popup', function() {
var p = {
link : function(scope, iElement, iAttrs){
//code to wrap the div (iElement) with a abs pos div (parentDiv)
// code to add a mask layer div behind
// if the parent is already there, then skip adding it again.
//use jquery ui to make it dragable etc.
scope.watch(showPopup, function(newVal, oldVal){
if(newVal === true){
$(parentDiv).show();
}
else{
$(parentDiv).hide();
}
});
}
}
return p;
});
See
http://adamalbrecht.com/2013/12/12/creating-a-simple-modal-dialog-directive-in-angular-js/
for a simple way of doing modal dialog with Angular and without needing bootstrap
Edit: I've since been using ng-dialog from http://likeastore.github.io/ngDialog which is flexible and doesn't have any dependencies.
Angular-ui comes with dialog directive.Use it and set templateurl to whatever page you want to include.That is the most elegant way and i have used it in my project as well.
You can pass several other parameters for dialog as per need.
Related
How to create a button (similar to FAB speed dial from angular material) or something similar to display a small window next to the button clicked, the small window only has a text area and a button inside, I would like to use Angular Material preferably or AngularJs routing or Jquery.
I have been trying using bottomsheets and FAB speed dial from angular material but without success.
I would appreciate any help.
If angular material doesn't have the functionality you are looking for built in (which I don't believe it does), you should just write a directive for it yourself. I would 'probably' write a directive that, when clicked, reveals a sibling or child element.
You could use a directive with a non-isolated scope to pass the data from the box you are creating to the rest of your application.
The code would probably look roughly something like this:
angular.directive('smallInputModalButton', function() {
scope: {}, // or false, up to you
controller: function () { $scope.isShown = false; },
template: '<div ng-hide="isShown"><input></input><button></button></div>',
link: function( scope, elem, attrs, controller ) {
elem.on('click', function(e) {
e.preventDefault();
scope.isShown = !scope.isShown;
});
}
}
Make sure you position the element that has the smallInputModal attribute on it relatively, with the #isShown div positioned relatively so that you can easily nest them next to each other.
If you want to be really thorough, you could create a directive that acts as a button, which communicates with another directive which has logic for showing/hiding the modal.
If you look in popular libraries, including ngMaterial, they do something of that sort.
For simple use cases, the answer above will work fine.
I've recently switched from jQuery to Angularjs and I am in the process of re-coding some pagination logic for the links ("Next", "Previous", etc.) that were written in jQuery-style Javascript previously.
Each link has an ngIf condition (for example, the "Previous" link won't show if you're on page 1) plus an ngClick event, which essentially updates a scope variable called $scope.pagination.position that determines which results are displayed in the table.
My original code was something like this (simplified for clarity):
Template
<a ng-if="pagination.position > 0" ng-click="pagination.first()">First</a>
Controller
$scope.pagination = {
first: function() {
this.position = 0;
}
}
Then I learned more about directives, and how most DOM elements that aren't static HTML should be created using a directive. So I switched each link (since each has it's own display rules and behaviour on clicks) to its own directive, like so:
Template
<a pagination-first></a>
Directive
app.directive('paginationFirst', function() {
return {
link: function(scope,el,attr) {
scope.pagination.first = function() {
scope.pagination.position = 0;
}
},
replace: true,
template: '<a pagination-first ng-if="pagination.position > 0" ng-click="pagination.first()">First</a>'
}
});
I'll cut straight to the chase : am I doing directives wrong? All that's happened, from my perspective, is I've flipped from having logic in my template to having a template in my logic, and I've defined the click event function in the directive rather than in the controller.
Is this even an appropriate time to be using a directive?
I'd like to learn best practices, so I'd love to know if I've missed the point and if the original templated-based ngIf and controller function approach was fine, even with longer and more complex ngIf conditions than the one shown.
If I want to add specific behaviors to a dom or dom list then I normally create a directive. As per angular js perspective the dom manipulation should only be done through directive (For me it is the best place, sometime I have to disobey this due to my lack of knowledge ). I specially found directive use full while creating a widget. In one of my project there was a part where a section is dedicated to display an image and also upload the image. I just use the directive on the top div, with the help of link function I attached the event handlers to various child dom. And as my project doesnot require an isolated scope (as this widget was all used in a single project and the outer scope was under my control) . So it worked like a charm. I cerarted the directive once. And used that widget through rest of the project as it's behavior and design (of the widget ) was same through out the project. For the pagination widget you can create a directive. Take the directive attibutes value as the input of the pagination parameters. Like calling script, limit offset. Container identifier to update the content. Then you can solely concentrate on the pagianation behavior. But from my experience (as I am also not so experienced in angular js), sometimes it becomes a little hectic to develop a directive and and use that throughout the project. As in some places we need to modify the behavior of the directive. And for this it may breaks elsewhere. But I know as I learn more I will be more efficient to handle this kind of situation. Hope my experience will help you.
I am trying to create a live HTML editor with AngularJS, where user can drag and drop some DOM elements to a container and it will render the final HTML page, for example, there is a button (or whatever) that says "Drag me to create an input", then user will drag that item into the container and an input field will be rendered...
I've been trying ngDraggable module but isn't what I needed...
I think a way is to hold the HTML code into some $scope variable, and when the user drops the button into the container, $scope.input which contains <input type="text" placeholder="Something"/> will be rendered inside container...
My final step is to enable inline edit to thoose HTML elements generated, in order to let the user create some content agains that final template.
When the user finish, the whole HTML code will be saved somewhere or downloaded...
I don't need something complex, just a few predefined elements that can be dropped...
I hope I've explained it correctly.
There is some example found at http://nboychev.com/tests/angular/Drag%20Drop%20iFrame%20using%20Angular%20JS%20Directive.html that does exactly what I want (see source), BUT:
It's using jQueryUI (Which I don't want to use, but if its needed then I will)
It isn't working on my project. I must say that I'm using RequireJS, but everything works on my angular app but the directives mentioned on the link above. Draggable is not working, I do not have any errors and I've checked that the code is being executed, doing some console.log() stuff, but still not working...
But it contains what I want, draggable stuff with HTML injected that renders content on an iframe (or a div, or whatever) and that new content is also droppable, to insert more stuff inside that code. Give it a try, and guide me a little. Thanks
I think it's better if you try using something as jui
On the other hand you can try implementing your own directive:
<br>
<h4>Drop Area</h4>
<div droppable jui-options="{addClasses: false}" class="drop-area"></div>
<div class="read-out">
<span class="text-info"><strong>Draggable ID</strong></span>: {{obj.id}}<br><br>
<span class="text-info"><strong>Content</strong></span>: <span ng-bind-html="obj.content"></span><br><br>
<span class="text-info"><strong>Actual Content</strong></span>: {{obj.content}}<br><br>
</div>
</div>
http://codepen.io/m-e-conroy/pen/jCdhu
Sounds like a fun project.
This is a simple link function using JqueryUI and Angular. You'll need an HTML element in scope with class "draggable". Use destroy() when finished.
Adding HTML to the DOM from the scope, check out this solution by Josh David Miller: http://jsfiddle.net/paulocoelho/fBjbP/2/
Or for simple HTML elements for visual display only you could try using ngBindHtml, ngRepeat and ngSanitize. Then adding / removing HTML elements to and from an array should display them in a container.
link: function($scope, $elem, $attr){
$elem.find(".draggable").draggable({
start: function(event, ui){
$(ui.item).addClass("shadow");
},
stop: function(event, ui){
$(ui.item).removeClass("shadow");
// DO SOME ANGULAR STUFF HERE
}
});
}
I'm working on a project and I am attempting to create a modal dialog "pop-up" to capture data in a form. I haven't worked with jQuery UI's Dialog widget previously, but I've worked with others and it seemed straight forward.
I created the following very simple code snippet to test as I went along:
<div class="app-email">
<div>
<a href="#"
class="app-email-opener">
Click to add or edit your e-mail settings.
</a>
</div>
<div class="app-email-modal">
Oh, Hai.
</div>
</div>
$('.content').on({
click: function () {
console.log('I was totes clicked.');
var parent = $(this).parents('.app-email');
console.log(parent);
var target = parent.find('.app-email-modal');
console.log(target);
$(target).dialog('open');
}
}, '.app-email-opener');
$('.app-email-modal').dialog({
autoOpen: false,
modal: true,
show: false
});
For reference: the class 'content' is a higher level block to catch delegated events without having to go all the way up the DOM.
The issue I'm running into is that the div with class="app-email-modal" seems to flash onto the page and then disappear from the DOM completely. jQuery, therefore, isn't able to find it and do anything because at that point it simply doesn't exist.
The overall project is in ASP.NET MVC 4, using Visual Studio 2013.
Any information would be greatly appreciated.
So, finally discovered what's happening via this previously answered question:
Jquery Dialog - div disappears after initialization
//EDIT
For any possible future usefuless -
What was happening was that jQuery UI will move any DOM elements specified as Dialogs to the bottom of the page, rather than keep them in the location specified in the HTML markup. So, in my case, I was looking for things by class, but only within the scope of the app-email-openers parent app-email div.
To remedy this, I used templating (in my case, Razor) to add unique ids to each app-email-modal div, and added a data- attribute to associate the link with the specific unique id. This way they jQuery UI can move the elements as it sees fit, but there still easily accessible.
//END EDIT
I feel like that functionality should be better spelled out in the documentation. Even their own example doesn't operate like this.
Corollary: I attempted to use the appendTo option to have the DOM elements not be shifted to the bottom of the page, but they're still moved to the bottom. So, there's that.
I know this has probably been asked before, but here goes: I have a web application that needs to generate modal dialogs. alert, confirm, and prompt are too simple and ugly, and that modal window function...it's a long story. I can't use it. So, I'm going to create the modal box using DOM functions and CSS. However, I need to put quite a lot of content into the dialog, and I'm wondering what the best way to do this is. Putting the HTML into a string and using innerHTML is unwieldy. I could use the DOM, but that's annoying and takes too much time to code. I know I can use a script with a weird type tag (something like x-random/x-htmlstuff) and then copy it's content to the innerHTML, but is there a better, more "official" way to do this?
if the layout of the modals are static, just put them into the HTML of the page. Use CSS to set them to display: none when the page is displayed normally. When you want to display the model, use
document.getElementById('modal-id').style.display = 'block';
I've heard that some people use this solution:
<script type="text/html" id="popup_html">
html...
</script>
(of course, you should make it invisible)
But, most likely, if you're trying to write a lot of HTML from javascript, then you should retrace and think if there's a better way.
If you're using the same div multiple times, you should just create it in the HTML page, and display it when needed
if you're creating a new element - see if you can use the document.createElement and appendChild methods (assuming there aren't many nodes involved)
if neither apply - retrace. For large projects, maybe object-oriented javascript can help.
There's no magical way that I'm aware of. I usually just use innerHTML and write the HTML out in a well formatting from such as:
box.innerHTML = "<div id='boxChild'>\n" +
" <p>Put whatever content here</p>\n" +
"</div>";
The \n make it so if you view your code, it will be well formatted, and no one long string once the JS writes it.
A way to do this, is to generate the popups within the html and show or hide them when you need, like this:
<div class="myPopup">
<div class="pop-message msg-01">This a pre generated alert with the id: <span class="dynamic-field-01"></span></div>
<div class="pop-message msg-02">This another pre generated alert with the id: <span class="dynamic-field-02"></span></div>
<div class="pop-message msg-03">...</div>
</div>
.pop-message {
display: none;
}
Now while user navigates the page, you are going to hide and show the .pop-message's while replacing those .dynamic-field's if needed.
I would suggest having the HTML for your modal content in separate files, and then loading it asynchronously when you need it to popup the modal.
partials/modal.html
<div class="content">My modal content</div>
main.js
var modalContent = null;
function _fillModal() {
modal.innerHTML = modalContent; // something like this
}
function openModal() {
if (!modalContent) {
// XMLHttpRequest, which populates the modalContent variable
// and in the callback, calls _fillModal()
}
// If already filled, just call
_fillModal()
}
If you want the content to be dynamic, make modal.html a template, and use a JS template library (for example http://underscorejs.org/#template), or write a simple RegExp replace yourself.
I'd suggest loading it with innerHTML or using jQuery to simplify things, but if you need
a modal window, could you use the jQuery UI modal dialog, shown here?
If you have the content loaded in divs in your HTML, and have them have css display:none;, and then show them with
document.getElementById("unshown-div").style.display="block";
If you can use jQuery, a modal box could be done with
<div id="modal" style="display:hidden">
Here is a modal dialog bbox
</div>
and your script:
$("#dialog").dialog();
Whatever you do, just don't use document.write()