Once we have a scope in hand, we can navigate to its root and explore the scope hierarchy.
But is there a direct way to find all the scopes on a page?
Likewise given an HTML element, is there a direct way to find its enclosing scope?
you can see all of the scopes on the page using this CSS selector
.ng-scope { border: 1px solid red; }
and all of the bindings:
.ng-binding { border: 1px solid red; }
You can then retrieve them by converting the DOM element into selector
var selector = angular.element(some_dom_element);
Then use the selector to retrive the scope/controller/injector
var scope = selector.scope();
var controller = selector.controller();
var injector = selector.injector();
Not all scopes are bound to elements. If you want all scopes on the page, walk the scope tree like this:
function getScopes(root) {
var scopes = [];
function visit(scope) {
scopes.push(scope);
}
function traverse(scope) {
visit(scope);
if (scope.$$nextSibling)
traverse(scope.$$nextSibling);
if (scope.$$childHead)
traverse(scope.$$childHead);
}
traverse(root);
return scopes;
}
getScopes($rootScope)
I don't know why this would be useful to you, but you can do this:
scopeElements = document.getElementsByClassName('ng-scope');
scopes = [].map.call(scopeElements, function(e){ return angular.element(e).scope(); })
The other option is to traverse the scope tree starting at the root scope using our private apis: $$childHead and $$nextSibling.
It's more likely that you just want to see where the scope boundaries are and you can do it with this:
scopeElements = document.getElementsByClassName('ng-scope');
angular.element(scopeElements).css('border', '1px solid red');
Then you can just use web inspector to select an element of interest and get its scope by:
angular.element($0).scope();
I recommend AngularJS Batarang. It's a debugging tool that lets you visualize all the scopes on the page (among other things).
https://github.com/angular/angularjs-batarang
You can find out a scope for element using:
$(element).scope()
or
angular.element(element).scope()
I don't think there is a way to get all scopes on a page easily (other than navigating down from root scope).
You should develop your application in Google Chrome browser (if you are not using it already) and than you can use awesome Batarang extension that adds new dedicated AngularJS panel to the Developer tools.
You can see all the scopes there, what is the relationships between them and what value have all its attributes.
http://blog.angularjs.org/2012/07/introducing-angularjs-batarang.html
In Chrome, using developer tools. I use the console command line.
Pick an element in the HTML panel of the developer tools and type this in the console:
angular.element($0).scope()
or just right click on a page element and select: inspect element.
$($0).scope() will return the scope associated with the element. You can see its properties right away.
To view an elements parent scope:
$($0).scope().$parent
You can chain this also:
$($0).scope().$parent.$parent
You can look at the root scope:
$($0).scope().$root
If you highlighted a directive with isolate scope, you can look at it with:
$($0).isolateScope()
If available, you can do the same with child scope and sibling scope.
$($0).scope().$sibling
I can walk up and down the scopes to verify what scope has what controllers, objects, etc and when you are working with custom directives, it's essential. In a large code base, it's not so easy to find things like this.
Recently, I had two controllers with the same name, save for one uppercase letter attached to a view. I was using the wrong controller and it took a while before I realized that was the issue with my bindings.
In Angulars there is $rootScope, which is the root of every scope.It has child field and whole hierarchy is inside $rootScope.If you want to find a scope with html element,you will probably have a problems,because that scope can be Isolated scope.Maybe you have a directive there,which scope is isolated.If you have anything like that,try to use el.isolatedScope()
Related
Is it possible to apply framework styles to nested lit-element? An idea is to disable shadow dom. I tried this.
createRenderRoot() {
return this;
}
It does not do what I need. I see that I can recompile styles into components. But right now I am looking for an easier solution.
There is a solution - Specify the render root. This solution rid of shadowRoot. Styles were applied but , does not work.
If you want to use global styles you'll have to disable Shadow DOM in the whole app tree: if a single component has a shadow root its whole subtree won't be affected by external styles.
Anyway, as you noticed, slots only work with shadow DOM enabled. In this case using a common style library/framework is still possible, see for example Sharing Styles, Using Bootstrap in Web Components, Importing external stylesheets.
Yes, but disabling shadow DOM is the wrong way to do it it.
LitElement used adopted stylesheets, which let you load/create the CSS once, but apply it to the shadow DOM of the component. You can create this globally, apply it in each component, and effectivly have styles that are shared by all your components, but (critically) don't apply to any external component you load or any external app that loads your component.
You can do something like:
// common-styles.js
export const styles = css`...`;
// any-component.js
import { styles } from 'common-styles.js';
...
static get styles () { return [styles]; }
As the styles object is shared it doesn't download or parse again - all your components get a reference to the same styles, rather than global styles cascading down.
It works as designed. The version above does not use ShadowDom. So styles are applied. In my case, all components while style bubbling has to disable ShadowDom.
But another issue appears.
createRenderRoot() {
/**
* Render template without shadow DOM. Note that shadow DOM features like
* encapsulated CSS and slots are unavailable.
*/
return this;
}
But I need slots.
It depends on what properties you want to share.
You can share these properties from the parent element:
color
font-family and other font-* properties
All CSS custom properties (--*)
Just you need to define these properties in the parent element's :root selector.
For more information: https://lit.dev/docs/components/styles/#inheritance
I want to embed a HTML file inside of my electron app. I chose to use iframe, however - when I do this - it seems like I can no longer use node.js. Any attempt at using require("electron") will show that require is not defined. Any ideas?
Thanks in advance!
Stijn
if you don't mind a late answer, you should probably use a <webview>, as it gives you a more fine grained control on what you need.
If, however, you really need to use an <iframe>, you have two choices:
use parent.require (parent accesses the iframe parent, which should be your window)
on the load event, copy the parent window's require to the iframe one:
iframe.onload = function () {
const iframeWin = iframe.contentWindow
iframeWin.require = window.require
})
The only "downside" is that your included packages will be accessing the main window DOM instead of the iframe's one, which means that none of the iframe window global variables will exist and, more importantly, document will access the window DOM (querySelector and getElemementBy methods won't really work). Whether this is a problem for you depends on how you organise your code, so good luck there
I am trying to build out a harness for a page so that we can write tests against it. What I would like to be able to do is use a CSS selector to find the given element or elements instead of manually modifying the SearchProperties or FilterProperties.For a web test the CSS Selector seems far more intuitive then the SearchProperties do. Is there some mechanism for doing this that I am simply not seeing?
Try this...
https://github.com/rpearsondev/CodedUI.jQueryExtensions/
It adds extension methods to the BrowserWindow object...
var example1 = browser.JQuerySelect<HtmlHyperlink>('a.class1');
var example2 = browser.JQuerySelect<HtmlListItem>('li.class2');
However, I will let you know I'm having issues with it complaining about casting errors regularly.
Try browserWindow.executeJavascript if you return a control you found via css/xpath it returns the relevant uiControl object
const string javascript = "document.querySelector('{0}');";
var bw = BrowserWindow.Launch(new Uri("http://rawstack.azurewebsites.net"));
string selector = "[ng-model='filterOptions.filterText']";
var control = bw.ExecuteScript(string.Format(javascript,selector));
HtmlEdit filter= control as HtmlEdit;
filter.Text = "Alien";
As sjdirect noted, the jQuery extensions are probably the way to go if you want to use those type of selectors.
However, it seems that you may be interested in some abstraction that doesn't require directly setting search / filter properties on the UITestControl objects.
There are good abstractions that do not use the same selectors as jQuery, but provide a readable, consistent approach for finding elements in the page and interacting with them.
I would recommend also looking into Code First and CodedUI Fluent (I wrote the fluent extensions) or even CodedUI Enhanced (CUITe).
These provide query support for that looks like (from CUITe):
// Launch the web browser and navigate to the homepage
BrowserWindowUnderTest browserWindow = BrowserWindowUnderTest.Launch("https://website.com");
// Enter the first name
browserWindow.Find<HtmlEdit>(By.Id("FirstName")).Text = "John";
// Enter the last name
browserWindow.Find<HtmlPassword>(By.Id("LastName")).Text ="Doe";
// Click the Save button
browserWindow.Find<HtmlInputButton>(By.Id("Save")).Click();
Goal: an encapculated widget
Suppose I'm the developer of a widget showing a list of friends, such as:
Your friends Michael, Anna and Shirley love this webpage!
First approach: script that creates span
Naively, I create a script which places this information in a span on the website. However, the owners of ExampleSite can now access the names of your friends by simple DOM operations!
That's a big privacy / security issue.
Second approach: an iframe
I don't want ExampleSite to have access to their friends' names. So instead, I let website owners add the widget with an iframe:
<iframe src="http://fakebook.com/friends?page=http%3A%2F%2Fexample.org%2F"></iframe>
This works, because the owners of ExampleSite cannot scrape the contents of the iframe. However, this whole iframe thing is rather ugly, because it does not integrate into the styling of the website, while a span does.
Desired approach: Shadow DOM
When reading about Shadow Dom yesterday, I wondered whether that could be a solution to both issues. It would allow me to have a script that creates a span the original website cannot access:
var host = document.querySelector('#friends');
var root = host.webkitCreateShadowRoot();
root.textContent = 'Your friends Michael, Anna and Shirley love this webpage!';
However, **does a Shadow DOM hide its contents from the surrounding page?**
The assumption here is that nobody except my script can access `root`, but is that correct?
The Shadow DOM spec after all says that it offers functional encapsulation, but I actually want trust encapsulation. And while the Component Model Use Cases actually list this use case, I'm not sure whether Shadow DOM realizes the necessary confinement property.
It does not, but it's in the works: https://www.w3.org/Bugs/Public/show_bug.cgi?id=20144
The encapsulation of trust will involve creating a new scripting context for each shadow tree, which is overkill for most scenarios. However, as the bug says, we'll add a flag (details TBD) that would allow this.
In Liferay I have used the asset publisher to publish news on my news page. I want to fetch the 3 top news from the page and embed it into another page. How can I do this? The page URL containing the news links looks like the following:
Liferay.Widget({ url: 'http://test.com/testnews/101_INSTANCE_f22'});
Liferay itself has a property where one can share an asset publsiher instance any where else on a site, but that is not exactly what I want. So any help or guidance is appreciated. Thanks.
If you want only links then you can set display style 'title-list' (this will take you to the article on the main news page).
if you want to open the link in another page, change asset link behavior to 'View in a specific portlet'.
You can change the look of asset publisher to whatever design you want. follow the path look & feel --> advanced styling --> Copy the portlet id. Now by using mozilla firefox pick the class,tags,etc. and write your css code. This will override the basic design. E.g.
#p_p_id_101_INSTANCE_8f5JPIxv8ml0_ .asset-abstract {
width: 25%;
float: left;
}
Is there a particular reason why you don't want to configure another AssetPublisher on the second page? You can just use the identical configuration, but limit the number of results shown to 3 - done.
Problem solved. Here is the solution with jQuery:
$.get('http://test.com/news/', function(data) {
var top3links = $(data).find('a:lt(3)');
$('#top3').html(top3links); // });