Use a component as the inline template for $mdDialog - angularjs

Typically you might show a dialog with Angular Material like this:
$mdDialog.show({
controller: FooCtrl,
templateUrl: 'app/foo_modal.html',
clickOutsideToClose: true
});
I would instead like to use a component in the inline template option. When I try to do that I see the screen dim, but the component's view is not visible.
It seems as though the component, auth-modal, is not rendered.
<div class="md-dialog-container ng-scope" tabindex="-1" style="top: 0px; height: 371px;">
<div class="md-dialog-focus-trap" tabindex="0"></div>
<md-dialog role="dialog" tabindex="-1" id="dialogContent_3" aria-describedby="dialogContent_3" class="md-transition-in">
<auth-modal></auth-modal>
</md-dialog>
<div class="md-dialog-focus-trap" tabindex="0"></div>
</div>

Here is a Plunker with a working example.
The example uses a component called user-detail in a dialog's inline template.
$mdDialog.show({
locals: { users: su },
controller: DialogController,
template: '<h2>Selected users ' +
'<button ng-click="closeDialog()">x</button></h2>' +
'<user-detail ng-repeat="u in users" user="u">' +
'</user-detail>',
});
If you are having a specific problem, please post the error message or some more info.

In my opinion it's better to use a 'dummy template' which is your <auth-modal> wrapped between <md-dialog aria-label="xyz"></md-dialog> tags - see this example along with the issue discussion. Then you could ditch the <foo-modal> (which I assume is the HTML snippet you posted) with the unnecessary md-dialog-container boilerplate code as $mdDialog service takes care of that for you.

Related

Angular component with transcluded markup

I am trying to create an Angular component and transclude the inner HTML of the component, but the markup of the inner HTML does not seem to be compiling. My use case for this is that the component has an attribute binding that I want to use in multiple ways, so the template will never be exactly the same.
For example, say I have the following simple controller:
class ComponentCtrl {
$onInit() {
this.variable = 'hello world';
}
}
let MyComponent = {
controller: ComponentCtrl
};
app.component('myComponent', MyComponent);
I want the following HTML:
<my-component>
<div style="color: green;">{{ $ctrl.variable }}</div>
</my-component>
<my-component>
<div style="color: red;">{{ $ctrl.variable }}</div>
</my-component>
to render as:
<div style="color: green;">hello world</div>
<div style="color: red;">hello world</div>
However, right now it is only rendering as:
<div style="color: green;"></div>
<div style="color: red;"></div>
without the markup being evaluated.
Is there something I'm doing wrong?
did you write the right name of controller inside your {{ }} in html? you wrote controller: ComponentCtrl and then {{ $ctrl.variable }}. it looks like they must have the same names
I think the problem come from {{ $ctrl.variable }}. In fact $ctrl try to link with a parent controller not with the controller of your component.
If you want interact with the controller of your component you need to use some parameter.
Transclusion is not made by default, you have to especify on your component that it has to be transcluded. Also, you didn't especify on your template where it should be trasncluded. Therefore, your component should look like:
let MyComponent = {
transclude: true, // tell angular to transclude it
template: '<ng-transclude></ng-transclude>', // tell where it will be transcluded
controller: ComponentCtrl
};
app.component('myComponent', MyComponent);
However, how was told on comments, component scopes are always isolated. Therefore, ou won't be able to access {{ $ctrl.variable }} from outside the component.
The transcluded content's scope has a $parent property that always points to the host component's scope.
So you could do something like this -
<my-component>
<div style="color: green;">{{ $parent.$ctrl.variable }}</div>
</my-component>
<my-component>
<div style="color: red;">{{ $parent.$ctrl.variable }}</div>
</my-component>
Plunk link that uses $parent property - http://run.plnkr.co/preview/ckdwiuzlb00073b661a7blt3f/

Abstract state with template in ionic

I am working with ui-router AngularJS in Ionic Project. I have an abstract state where I nest my children's templates via <ion-nav-view> tag. The question is can I display some default data in the template of the abstract state that will be shown for all the children's templates ?? If no then Why. I tried this simple example
<ion-view view-title="MyView">
<div>
<h1>Welcome</h1>
</div>
<ion-nav-view name="ChildContent"></ion-nav-view>
</ion-view>
But the message Welcome is not shown. The space for the div is there but nothing is displayed.
I think I found the solution. What I ended with to not repeat the same info within all the children templates is to create a custom directive with its own template and just include this directive in every child's template. So, we just have one place to manipulate. It is the section "Template-expanding directive" in Angular documentation. More informations could be found in this link : enter link description here. Hope it will help someone else :) .
You can define a controller for your abstract state and there setear default values that can be displayed in various other views. You can also do this in the function
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
.controller('AppCtrl', function($scope){
$scope.title = "Test title";
})
OR
angular.module('started.controllers', [])
.run(function($window, $rootScope) {
$rootScope.title = "Test title";
});
<ion-view view-title="{{title}}">
<div>
<h1>Welcome</h1>
</div>
<ion-nav-view name="ChildContent"></ion-nav-view>
</ion-view>

ui-router: intermediate templates

Final Edit: working plunker with the transcluded directive.
Edit: I made a first plunker with the solution given in the first answer. It works, but it's not the desired behaviour, because the template contains all the partial.
I made a second plunker with what I hope to achieve (but it doesn't work, obviously). I think it's mostly because the template is not the parent of the partial, but it is contained in it, so ui-router doesn't understand very well what I want.
Any help with this would be greatly appreciated!
We are building a website with Angular Material and ui-router, and all our content page share the same "container", because we always want the same responsive behaviour.
The code of this generic container would be something like:
<div class="layout-content">
<div layout="column" layout-align="center">
<div layout="row" layout-align="center center">
<section class="layout-fixed-width md-whiteframe-z1" flex-sm="100" flex-gt-sm="90">
{{content placed here}}
</section>
</div>
</div>
</div>
The header can differ in all pages, so the structure we have would basically be:
The question is, how can this be achieved in ui-router? We have done some nested views, but I don't see how to do a generic template so the code could be something like:
<form>
<md-toolbar/>
<div ui-view="generic-template">
<div ui-view="my-content"></div>
</div>
</form>
Ideally we would want to define only one time the generic-template view, and use it in all our modules.
In the nested states and nested views documentation I see mostly nested state stuff, but what we want is really only a plain html template, so maybe we are over-complicating this, and an easier way is possible (I'm quite sure it's the case). I've also checked this issue, where one of the answers say that ui-router should be the solution, but not much more.
Maybe we should do a directive instead?
It can be achieved combining named views and abstract states.
The 'key' here is to define an abstract state with a view for the layout (or generic template, if we follow the nomenclature of your original post).
Abstract state:
.state('master', {
abstract: true,
views: {
generic_template: {
templateUrl: 'genericTemplate.html'
}
}
})
Then, you have to set this abstract state as parent to the child views. So, the child view will inherit the generic template view. Example:
.state('one', {
url: '/one',
templateUrl: 'one.html',
parent: 'master'
})
In your index.html, you have to use a named view for the generic template, and inside it, another unnamed view. Something like this:
<body>
<div ui-view="generic_template">
<div ui-view></div>
</div>
</body>
Here is a plunker with a complete working example.
Hope it helps.
Maybe we should do a directive instead?
A directive with a transcluded ui-view certainly seems to give you what you're looking for. This saves you from cluttering up your routing logic with something that has nothing to do with routing.
genericTemplate.html:
<div>
<p>Generic content</p>
<ng-transclude></ng-transclude>
</div>
Somewhere in your js:
angular.module('formApp')
.directive('genericTemplate', function () {
return {
replace: true,
transclude: true,
templateUrl: 'genericTemplate.html'
};
});
In your html:
<body ng-app='formApp'>
<div generic-template>
<div ui-view></div>
</div>
</body>
Edit: working plunker

using ng-view for hightly dynamic content?

I'm working on a website that allows you to search for different products, for example laptops. This is my index div:
<div class="content" id="main">
<div id="search-wrap">
<div id="logo"><h1>seach</h1></div>
<form id="search">
<input type="text" placeholder="Search " autofocus ng-model="query"/>
</form>
<div style="border: solid 1px blue" ng-show="query">
<ul ng-repeat="x in [] | range:10">
{{ query }}
</ul>
</div>
</div>
I have not yet implemented angular js on this but I'm thinking about how to do it. I'm not sure how to approach this, since its a complex site. Once a user searches for something, they will get results from a product. Will i have to create a different ng-view?
I'm just going by something i read online:
A page gets one ng-view. Assuming you have a single page application, this means you get one view. Use it wisely. Give some thought to what should be in the view. Is this your main content window or is this more of a navigation? Is the actual content (HTML) of this section highly dynamic? These are important decisions to make early in the development of your application if you have more than one distinct content area on your page.
Sorry if my question doesn't make sense, just not sure what to ask. Any tips will help.
thanks
You better try using ng-view and you would get more idea how it works.
There can be one ng-view in a page and it is tightly integrated with the url. When you change urls in browser, effective you are loading a different view into the ng-view area. These are configured using the $routeProvider.
ng-view is like the central content theme\area. Other views including sub-views for the main view and left nav, top nav footer is loaded using ng-include directive which has capability to compile and load any html chunk from server or locally.
For complex routing needs please have a look at ui-router which supports nested views.
For complex view you can try something like this
$stateProvider
.state('login', {
url: '/login',
controller: 'LoginController',
templateUrl: 'login.tpl.html',
access: 0
})
.state('multiple view', {
url: '/main',
access: 1,
views: {
'#': {
templateUrl: 'view1.tpl.html',
controller: 'view1Controller'
},
'page#dashboard': {
templateUrl: 'page.tpl.html',
controller: 'pageController'
}
}
})
More Info

Angular UI Bootstrap Modal strips id and class attributes

Live Example
Adding the following Angular UI Bootstrap Modal:
<div id="my-id" class="my-class" modal="opened">
<p>Modal Here</p>
</div>
results in:
<div class="modal ng-scope">
<p>Modal Here</p>
</div>
Why the id and class attributes are stripped?
I would like to set some CSS styling on the dialog, e.g. dialog's width, or styling some dialog's inner elements. How could I achieve that?
Because I just came across this irritating issue myself and the documentation and default behavior isn't obvious. You can now pass in additional classes via the $modal.open() method using the windowClass option:
var modalInstance = $modal.open({
templateUrl: 'templateUrl.html',
controller: Controller,
windowClass: 'custom-css-class',
...
});
Can't set an ID though which is lame. More info in the official angular-ui modal docs.
Here's the github issue explaining why the id is being stripped.
As for the class, I'm not sure why's that stripped, but you can use $dialog options to specify the class (which will fix your issue):
<div id="my-id" modal="opened" options="{dialogClass: 'modal my-class'}">
<p>Modal Here</p>
</div>

Resources