Access elements in Angular Dart - dart

I have a top level element <x-app> with nested modal dialogs
<x-app>
<material-content>
...
</material-content>
<x-alert-dialog></x-alert-dialog>
</x-app>
where <x-alert-dialog> contains
<modal [visible]="dlgVisible" dialog-id="alert-dialog-modal">
<material-dialog class="alert-dialog">
....
</material-dialog>
</modal>
Generated HTML contains <x-app> and overlay container div which contains modals as on the image
What I need is to access <div pane-id="default-1"...> to change z-index. and I don't know how. I cannot access it in CSS as any reference via :host is not possible.
I tried to access it programatically in x-app component. I have
class AppComponent implements AfterViewInit {
#override
void ngAfterViewInit() {
var doc = getDocument();
var alertDlg = doc.querySelector(".alert-dialog");
var alertPane = alertDlg.parent;
}
}
But alertDlg is always null. I also tried var alertDlg = querySelector(".alert-dialog");
Is there any way to access the element?

I solved it by adding *ngIf="dlgVisible" to <modal> tag, so it's now
<modal *ngIf="dlgVisible" [visible]="dlgVisible" dialog-id="alert-dialog-modal">
This way the dialog is injected to/removed from DOM by the visibility flag. The reason why I wanted to change z-index was to get the alert and other app wide dialogs above other dialogs created later in other components.
Altering DOM solves this as the dialogs are inserted after (and thus displayed above) other dialogs. Hope this will help someone.

Related

How to remove "on-click" from a custom Polymer component

I have a custom button component done in Polymer Dart:
<div id="buttonDiv">
<my-button id="traceButton"
mode="icon" faicon="fa-comment-o"
toolTip="Print a simple comment"
disabled="false" on-click="{{ traceSomething }}">
</my-button>
</div>
I'm trying to copy/paste this button somewhere else. So a user defines it somwhere, and I basically move it by way of getting $['buttonDiv'].children then inserting it somewhere else. The problem is that {{ traceSomething }} is now irrelevant since it's not part of the new parent. I get errors saying that the parent object, which is another polymer component doesn't have an instance getter "traceSomething".
My question is, is there a way to remove "traceSomething" before I insert it somwhere else? I tried removing the "onClick" event listeners, but the buttons still wants to call that function upon click. Also, I've tried adding a preventDefault, etc, like in: In Dart, if I listen to a click event with two listeners, how do I know which happens first?
But, no luck.
I'm not sure what you mean by copy/past. Do you clone the element, or do you just append it to some other elements children.
Anyway, I don't think you can remove the event listener if it was added declaratively. If you add it imperatively it is easy to remove and readd later.
import 'dart:async';
...
StreamSubscription subsc;
#override
attached() {
super.attached();
subscr = onClick.listen((e) => (this.parentNode as ShadowRoot).host.traceSomething(e));
}
#override
detached() {
super.detached();
if(subscr != null) {
subscr.cancel();
}
}
See also https://stackoverflow.com/a/22168745/217408 about accessing the parent of a Polymer element (for Dart Polymer <= 0.16.x)

Event when an Component is added to the dom

Say I have a AngularDart component that adds a div and an iframe to that div as it's template.
I have the element passed for the outer component in the components constructor
#Component(
selector: "input-html",
templateUrl: "packages/myproject/components/inputs/html.html",
useShadowDom: false
)
class HtmlComponent implements ShadowRootAware {
HtmlComponent(NgModel ngModel, Element element):super(ngModel, element){
}
}
I have shadowdom turned off because I'm using Bootstrap for styling and want the elements easily accessible for the bootstrap css.
My template code is along the lines of
<div>
<iframe id="my-iframe"></iframe>
</div>
It's more complicated than that, there's a bunch of buttons etc, as I'm porting a javascript html editor to angulardart.
My problem is, I need to get the iframe element, but whenever I query element.querySelector("#my-iframe") or even window.document.querySelector("#my-iframe") the object is null. I believe this is because the template hasn't been added to the DOM yet.
I need the iframe object because I need to set the iframe content for the HTML editor to work. There's a few other areas of my project that I wanted to get the template dom objects but couldn't either.
I've tried onShadowRoot, which worked in AngularDart 0.14 but no longer works in 1.0. I've tried ScopeAware and querying for the iframe when the scope is set, but that didn't work (ScopeAware fires before shadowroot event).
I have a hack that's messy that works, by using ng-show="init()" and in that init method I have
bool _initDone = false;
bool init() {
if(_initDone == false) {
iframe = element.querySelector("#my-iframe")
_initDone = true;
}
return true;
}
Which works, but it's messy and I don't like that solution and obviously isn't the correct way to do it.
Anyone know how I can achieve this in AngularDart 1.0?
I think onShadowRoot is the right place for the code to query the element. If it really doesn't work wrap it in a Future to add it as a task at the end of the event queue to delay it a bit more.
onShadowRoot() {
new Future(() {
querySelector(...);
});
}

angular.dart how to create a custom component programmatically and add to page?

Is it possible to define an angular-dart component and then programmatically create an instance of that component and add it to your web page? I'd hoped there might be something like:
import 'package:web_sandbox/web_sandbox.dart';
import 'package:angular/angular.dart' as ng;
void main() {
document.body.appendHtml('<web-sandbox-component></web-sandbox-component>');
var node = document.body.query('web-sandbox-component');
ng.compile(node);
}
is there away of creating an angular web component programmatically and adding it to the page, maybe like the above pseudo-example, and if so how?
I don't think this is possible with Angular.
You can add an HTML tag <web-sandbox-component> into the DOM and tell Angular it should process this new HTML and then Angular would instantiate the Angular component for this tag (this is what the question you linked is about).
I don't see this as a limitation.
Is there something you would like to do that seems not possible this way?.
EDIT
Your code in main should look like this:
my document looks like
...
<body>
<div id="mydiv"></div>
...
</body>
and I append the <web-sandbox-component> to the div
main() {
print('main');
ng.Injector inj = ngaf.applicationFactory().addModule(new MyAppModule()).run();
var node = dom.querySelector('#mydiv');
node.append(new dom.Element.html('<web-sandbox-component></web-sandbox-component>', validator: new dom.NodeValidatorBuilder()..allowCustomElement("web-sandbox-component")));
ng.Compiler compiler = inj.get(ng.Compiler);
ng.DirectiveMap directiveMap = inj.get(ng.DirectiveMap);
compiler(node.childNodes, directiveMap)(inj, node.childNodes);
}

How to overlay xul with no id?

I'm writing a firefox addon and I'm trying to use an xul overlay to insert a canvas element. The problem is, the parent xul node of where I want to insert the canvas element has no id. Is it possible to do if there's no id? I also tried using the anonid for elements that had no id as you can see below, but had no luck with that either.
My xul overlay:
<?xml version="1.0"?>
<overlay id="myOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<tabbrowser id="content">
<tabbox anonid="tabbox">
<tabpanels anonid="panelcontainer">
<notificationbox>
<stack anonid="browserStack">
<html:canvas id="myCanvas" height="100%" />
</stack>
</notificationbox>
</tabpanels>
</tabbox>
</tabbrowser>
</overlay>
I would like the canvas element to be inserted after each browser element in each tab like this: http://img.photobucket.com/albums/v215/thegooddale/80eae9ee.jpg
There are multiple issues with the attempt to use overlays for this:
Overlays don't work without an ID, they simply don't have another way to address an element.
Overlays cannot apply to something that isn't there when the window loads - they are a one-time thing and cannot consider dynamic elements that are created later.
Overlays cannot apply to anonymous elements (displayed in red in DOM Inspector). These elements are injected by an XBL binding and are not part of the XUL document.
You will have to use JavaScript and inject your canvas "manually" each time. You can use the TabOpen event to get notified whenever a tab is opened. Something like this should work (untested code):
// Always wait for the window to initialize first
window.addEventListener("load", function()
{
function initTab(tab)
{
var browser = window.gBrowser.getBrowserForTab(tab);
var canvas = document.createElementNS("http://www.w3.org/1999/xhtml",
"canvas");
canvas.setAttribute("anonid", "myCanvas");
canvas.setAttribute("height", "100%");
browser.parentNode.appendChild(canvas);
}
// Init all existing tabs first
var tabs = window.gBrowser.tabs;
for (var i = 0; i < tabs.length; i++)
initTab(tabs[i]);
// Listen to TabOpen to init any new tabs opened
window.gBrowser.tabContainer.addEventListener("TabOpen", function(event)
{
initTab(event.target);
}, false);
}, false)
Note that this code sets anonid attribute rather than id - an ID is supposed to be unique, you shouldn't assign the same ID to a dozen elements.
This won't work without an id. You could insert a piece of Javascript in the XUL document, that uses document.querySelector to find the tabpanels inside your XBL binding, and then would append the dynamically-created canvas to id.
However, since a new notificationbox is created every time a new tab is opened, you should have your javascript watch for new tabs and insert the canvasses accordingly.

How to call a MXML class in ActionScript3.0 in Flex 3

I have a page made of custom components. In that page I have a button. If I click the button I have to call another page (page.mxml consisting of custom components). Then click event handler is written in Action-script, in a separate file.
How to make a object of an MXML class, in ActionScript? How to display the object (i.e. the page)?
My code:
page1.mxml
<comp:BackgroundButton x="947" y="12" width="61" height="22"
paddingLeft="2" paddingRight="2" label="logout" id="logout"
click="controllers.AdminSession.logout()"
/>
This page1.mxml has to call page2.mxml using ActionScript code in another class:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
}
Your Actionscript class needs a reference to the display list in order to add your component to the stage. MXML is simply declarative actionscript, so there is no difference between creating your instance in Actionscript or using the MXML notation.
your function:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
}
could be changed to:
static public function logout():StartSplashPage {
return new StartSplashPage();
}
or:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
myReferenceToDisplayListObject.addChild( startPage );
}
If your actionscript does not have a reference to the display list, than you cannot add the custom component to the display list. Adding an MXML based custom component is no different than adding ANY other DisplayObject to the display list:
var mySprite:Sprite = new Sprite();
addChild(mySprite)
is the same as:
var startPage:StartSplashPage = new StartSplashPage();
myReferenceToDisplayListObject.addChild( startPage );
Both the Sprite and the StartSplashPage are extensions of DisplayObject at their core.
You reference MVC in the comments to another answer. Without knowing the specific framework you've implemented, or providing us with more code in terms of the context you are trying to perform this action in, it is difficult to give a more specific answer.
I assume that you are on a page with a set of components and want to replace this set of components on the page with a different set of components. My apologies in advance if this is not what you are trying to do.
You can do this using ViewStacks and switching the selected index on selection -- this can be done either by databinding or by firing an event in controllers.AdminSession.logout() and listening for that event in the Main Page and switching the selectedIndex of the view stack in the handler function.
MainPage.mxml
<mx:ViewStack>
<views:Page1...>
...
<comp:BackgroundButton x="947" y="12" width="61" height="22"
paddingLeft="2" paddingRight="2" label="logout" id="logout"
click="controllers.AdminSession.logout()"/>
</views:Page1...>
<views:Page2 ...>
...
<comp:Comp1 .../>
<comp:Comp2 .../>
</views:Page2>
I think you may use state to do you work.
You may take a look at http://blog.flexexamples.com/2007/10/05/creating-view-states-in-a-flex-application/#more-221
Edit:
I am not sure I fully understand your case.
As I know, you may make a new state in page1.mxml, and name it, eg. secondPageState, and then put the custom component page2.mxml in the secondPageState.
In the controller, you need an import statement to import the page1 component and make a public var for the page1 component, eg. firstPage.
Then, the code will similar to:
public function logout():voild
{
firstPage.currentState = "secondPageState";
}
Another solution:
If you don't like the change state solution, you may try to use the addchild, to add the custom component to your application.

Resources