AngularStrap - load template file in modal template as inner content - angularjs

I'm new to Angular-strap and AngularJS. I'm working on a project that is gonna be using both of them.
Scenario
My idea is to have multiple Modal template files for Angular-strap (w/ header, w/ header and footer, etc.). In some of these templates I would like to load different HTML file, so the Modal template file can be like a wrapper. The idea is that these different HTML files will have their own controllers and scopes. I would like to use those scopes in Modal template files to display specific data like: title, buttons, text of buttons, etc.
Problem
Seems like I'm not able to use both data-template-url and data-content-template (or at least it's not working on my side). I can use one of them, for example, in this case below, only data-template-url is used.
<button type="button" class="btn btn-lg btn-danger" data-animation="am-fade-and-slide-top" data-template-url="views/mb-templates/popups/dialog-simple.html" bs-modal="modal" data-content-template="views/mb-templates/dialog-inner-content.html">Custom Modal
<br />
<small>(using data-template)</small>
</button>
Questions
Is it possible to create the scenario that I've described?
If it is, how this can be done?

It should be possible if you use templateUrl to return a function, and within the function you make your conditional template selection. The Angular Directive documentation's section on a "Template-expanding directive" has a good example. Here's a link to the Template-expanding directive example's Plunker. The example's directive code looks like this:
.directive('myCustomer', function() {
return {
templateUrl: function(elem, attr){
return 'customer-'+attr.type+'.html';
}
};
});

Related

Passing multiple 'button' parameters to Angular component

I'm creating a reusable item picker component using Angular 1.5. The picker has a search field and a list of items to choose from. An example use case for the picker is a popup where the user selects some items and then has a "Continue" button to proceed.
Conceptually, the search field and the list of items belong to the component and the "Continue" button belongs to the surrounding dialog. However, I want to position the button next to the search field. In some cases there are no extra buttons, sometimes one extra button, sometimes two.
Something like this:
What is the best way to create such a component?
Options I've thought of:
Create a component / directive for the item picker, put the button before or after the directive in the HTML, and use CSS to position the button.
Here the positioning of the button is ugly and fragile, as it's not in the proper position within the HTML. It would probably need a wrapper div and absolute positioning on top of the picker component:
<div style="position: relative">
<item-picker></item-picker>
<button name="Continue" ng-click="submit()" style="position:absolute; top:5px; right: 5px"></button>
</div>
Somehow pass the buttons and callbacks as parameters to the item picker component. Here the ugliness is in the hard-coding of the buttons and styles and amount of buttons:
<item-picker btn1-text="Continue" btn1-style="primary" btn1-callback="submit()" btn2-text="Cancel" btn2-style="secondary" btn2-callback="cancel()"></item-picker>
I'm unsure whether the button configuration and callbacks could be passed as a single configuration object. I'm mainly concerned about the callback functions, whether they will work properly if passed through a configuration object instead of proper '&' callback binding.
Stop trying to make the picker into a component / directive and just use <ng-include> to include the picker code which reads the button configuration from the scope. Ugliness is in lack of scoping and not using components.
Is there some best practise for such cases?
One possible solution is to use ng-transclude, so your code could look something like:
Markup
<item-picker>
<button ng-click="parentScopeFn()">Btn 1</button>
...
</item-picker>
Directive
angular.module('myApp', [])
.directive('itemPicker', function() {
return {
restrict: 'E',
transclude: true,
scope: {
...
},
templateUrl: 'item-picker.html'
};
});
itemPicker template markup
<div class="item-picker">
<div class="item-picker-controls">
<div class="item-picker-search"><input type="search" ng-model="..."></div>
<div class="btn-group" ng-transclude></div>
</div>
<ul class="item-picker-list">
<li ng-repeat="item in items" ng-bind="item"></li>
</ul>
</div><!-- end item-picker template -->
Of course the above code is just an example and is making a lot of assumptions about your itemPicker component. Also, you'll still need to use CSS to position your buttons, but it might be easier to reason with b/c it'll be in the context of your component.
Note
You could also make use of "multi slot transclusion". This is probably useful in cases where the number and type of buttons you'll have is predictable and you want them arranged in a consistent way no matter how they are placed in the markup.
Hope this helps.

ngDialog - how to close dialog from the template (i.e. no controller functions)?

On ngDialog (https://github.com/likeastore/ngDialog), is there a built in way to close a dialog from within the template it self? I.e. so I don't need any functions in the controller calling the dialog?
This is my template (errorPopup.html):
<div>
<div class="alert alert-warning">
<div class="errorLogo"><i class="icon-exclaim"></i></div>
<div class="errorContent" data-ng-bind-html="errorMessage"></div>
</div>
<div class="buttonWrapper">
<button type="button" class="btn-primary pull-right">
<span res="close"></span>
</button>
</div>
</div>
And this is how I open the dialog:
function showErrorPopup() {
ngDialog.open({
template: 'errorPopup.html',
scope: $scope,
className: 'ngdialog-theme-default ngdialog-cart-theme',
showClose: true,
appendTo: 'div[ui-view]',
closeByDocument: false
});
}
So when I call showErrorPopup() I get a dialog displayed, however, I need to make this "close" button to actually dismiss/close the popup. As of now, this is just a plan button that doesn't do anything.
Is there something I can do a the template level (without changing my controller's code) to make the button work?
Maybe I should be using a default button instead of my own? If so, how?
PS: I notice thats clicking on the X button on the top right works, the popup is dismissed.
Thanks all!
You don`t have to inject ngDialog module in your $scope. You can call closeThisDialog() function in your popup template directly:
<button ng-click="closeThisDialog(0)">Close</button>
function argument is the value to resolve popup with.
If you want to call the close function of the ngDialog directly from the view, you must inject the module itself to the scope inside the controller, in order for it to become available from the view:
$scope.ngDialog = ngDialog;
Then, you can use it directly from within the view:
<button ng-click="ngDialog.close()">Close</button>
It is hard to say what exactly you are doing wrong, until you paste some controller and app.js and HTML code contents.
Yes, ngDialog has built-in way of closing the dialog
Make Sure you set the className to 'ngdialog-theme-flat ngdialog-theme-custom' or other css class as described in the docs inside open function.
You have added handler with name "closeThisDialog" , but function has another name "closePopup".
Maybe it is your issue.
just follow these steps
1.when creating app
var app = angular.module('sampleApp', ['ngDialog']);
2.use button like this
<button ng-click="clickMe()">Click to Open</button>
3.put this in your controller
`$scope.clickMe = function () {
ngDialog.open();
};`
by default it has code to close,It'll close automatically when you click on close.
Hope it'll be useful

Rending a Modal in AngularJS

I'm attempting to learn AngularJS (background in BackboneJS). I have a div with some content inside, and I hope to render this div as a modal upon clicking inside of it:
<div class="stickynote"> Content here </div>
My thinking is to add a modal class that I can style in CSS. However, I'm not too sure how to add the modal class upon clicking (and conversely, removing the modal class upon clicking after the modal is rendered). Would I have to use ng-click and somehow set the class property from the JavaScript (myApp.js) file?
If you want to use your own modal styling and if you simply want to achieve adding an extra item to class attribute of your element, you can use a combination of ng-class and ng-click:
<div class="stickynote"
ng-class="{yourModalCSSClass: isModalOpen}"
ng-click="isModalOpen = true">
And somewhere else, you need another ng-click to turn it off:
<button ng-click="isModalOpen = false">Close modal</button>
Beware that both div and button must be in the same scope hierarchy to be able to use the same isModalOpen value. And by the way, I haven't tried this code but this should give you an idea. If you have a controller/directive, you can set isModalOpen from there by introducing functions in the scope:
// controller
$scope.toggleModal = function () {
$scope.isModalOpen = !$scope.isModalOpen;
}
<div ...
ng-click="toggleModal()">
<button ng-click="toggleModal()">...
If you're open to using a third-party solution, ng-dialog is an outstanding solution for modals+Angular.
https://github.com/likeastore/ngDialog

How to create reusable custom directives in angular JS

How can one create a reusable model window in AngularJS?
I'd like it to be reusable in the sense that we trigger the modal window with a hyperlink and set the popup content based on the parameter passed. For example:
<div ng-controller="SampleCtrl">
<a ng-click="toggleModal('FirstParam')">first</a>
<a ng-click="toggleModal('SecondParam')">second</a>
<a ng-click="toggleModal('ThirdParam')">Third</a>
</div>
When the first link is clicked it would display a modal containing content related to "FirstParam", etc.
I've tried custom directives and using $parent but I don't know how to pass the parameter from the toggleModal function call into the custom directive.
How can I achieve a re-usable modal window that is similar to this example?
In particular, I would like to know:
How can I pass variables from a controller function into a custom directive?
Are there any good tutorials on reusable custom directives and scopes?
Are there any other design patterns for reusable custom directives?
Checkout http://egghead.io for some basics on writing custom directives, also the angular docs on directive and compile have all the details https://docs.angularjs.org/guide/directive https://docs.angularjs.org/api/ng/service/$compile
Here's a plnkr I posted with an overridden template for the popover from ui-bootstrap. Depending on your exact use case you may be able to get away with just overriding a template or else making a directive that makes use of $modal or some other modal UI control http://plnkr.co/edit/eeiJ5re7mNdhHNDEeCQO?p=preview
// Code goes here
angular.module("myApp", ["ui.bootstrap", "ngSanitize"]).controller("TestCtrl", function($scope){
})
angular.module("template/popover/popover.html", []).run(["$templateCache", function ($templateCache) {
$templateCache.put("template/popover/popover.html",
"<div class='popover {{placement}}' ng-class='{ in: isOpen(), fade: animation() }'>" +
"<div class='arrow'></div><div class='popover-inner'>" +
"<h3 class='popover-title' ng-bind='title' ng-show='title'></h3>" +
"<div class='popover-content' ng-bind-html='content'></div>" +
"<button class='btn btn-cancel' ng-click='manualHide()'>Cancel</button>" +
"<button class='btn btn-apply' ng-click='manualHide()'>Apply</button></div></div>");
}]);

Using a directive to add content to areas outside ng-view

I'm attempting to port an existing Ruby on Rails frontend to Angular. So far I've managed to get a single page app in place that switches out the content of ng-view depending on your angular route. This is great, however - in my RoR layout I have several defined areas where content can be placed, all of these are contextual to the main view. For example: Sidebar and Heading.
In RoR I can do the following from within an action view to set sidebar content.
<p>Product page content</p>
<% content_for :sidebar do %>
<% render :partial => 'product_sidebar' %>
<% end %>
I am struggling to determine the best method to achieve this in Angular. I've got it working with two methods:
SidebarUrl added to route definitions, route change event updates a scope variable which an ng-include directive uses in the layout.
Custom directive that is served with the template loaded into ng-view, e.g.
<p>Main content for the view</p>
<sidebar>
Content for sidebar
</sidebar>
The directive basically copies its innerHTML to the sidebar element in the main layout and then removes itself. It could be written to place the content into a target element defined by an attribute to make it more generic and reusable.
This way is more natural to me as the result is closest to the Ruby on Rails way but I'm not sure if its a decent solution or something that I will run into problems with later on (I'm very new to Angular).
Any thoughts or suggestions welcome.
UPDATE 18/06
I've found the Angular UI Router project: https://github.com/angular-ui/ui-router which seems to cover my requirements in an official way. Leaning towards that as a solution at the moment.
Try this (not tested).
You can have another element outside of your <div ng-view> element: say, <div id="sidebar" ng-controller="sidebarContr">. Since you can inject as many dependencies as you like in to sidebarContr, you can use $location as one of its parameters and check the location there and add properties to $scope to make the div display what you need.
For example:
in your controllers JS:
(angular
.module('app.controllers', ['ng'])
.controller('sidebarContr', [
/******/ '$scope', '$location',
function ($scope, $location) {
if ($location.path() === '/') {
$scope.file = 'include_0.html';
else {
$scope.file = 'include_1.html';
}
}
])
);
in your HTML:
<div id="sidebar" ng-controller='sidebarContr'>
<div ng-include src='file'></div>
</div>
EDIT: The Angular-UI Router component that you mention seems to be what you need, it looks more powerful. But my solution can be useful when you just need something simple and do not want to have one more dependency.

Resources