I've extended an element with
const PaperSliderClass = customElements.get('paper-slider');
class MyPaperSlider extends PaperSliderClass {
...
But how do I tell the polymer linter/build about it?
I tried to add the following right before my class declaration, but it didn't work.
/**
* #polymer
* #customElement
* #extends {PaperSliderClass}
*/
apparently I could just do:
#appliesMixin paper-slider
Related
My function isn't called when I click the <a... tag.
I have the following code in my component:
public htmlstr: string;
public idUser:number;
this.idUser = 1;
this.htmlstr = `<a (click)="delete(idUser)">${idUser}</a>`;
public delete(idUser){
alert("id " + idUser);
}
My html
<div [innerHTML]="htmlstr"></div>
but the function delete isn't called and does not show the alert.
The <div... is created dynamically
If anyone face same issue and above all answer not working then try my trick :
In HTML :
<button onclick="Window.myComponent.test()"> test </button>
In component :
class
constructor(){
Window["myComponent"] = this;
}
test(){
console.log("testing");
}
Your main issue here, on-top of the things pointed out by #Matt Clyde and #Marciej21592, is that you're trying to dynamically add HTML code that needs to be compiled before it can be used (you're trying to bind to a method and variable).
Some ways of doing this can be seen here.
From the code you have supplied, however, there are much easier ways to accomplish what you are after. For starters, I would have that code in the HTML to begin with and hide/show it as needed with ngIf.
i use this method and its work
public htmlstr: string;
public idUser:number;
this.idUser = 1;
this.htmlstr = `<a id='innerHtmlClick'>${idUser}</a>`
this.htmlstr.querySelector(`innerHtmlClick`).addEventListener('click', () => {
this.delete(idUser);
});
public delete(idUser){
alert("id " + idUser);
}
EventListener listen the event bye using id of innerHtml
I assume that it is not a bug but rather Angular's security measure against XSS attacks - for more information I would suggest taking a look here https://angular.io/guide/security#sanitization-example
I somewhat also fail to understand why you insist on passing the event via string literal instead of just simply using:
<div>
<a (click)="delete(idUser)">${this.idUser}</a>
</div>
Your component has inner Html.
Angular will not allow events inside inner Html portions for security reasons. You can use Child components. to make events from inside of inner Html portions. Create a child component and put your html inside the child component and pass the data by using any angular events between parent and child using Input, Output features in Angular
I don't often use [innerHTML], but it looks like the template string you're using <a (click)="delete(idUser)">${idUser}</a> is referencing ${idUser} when you might have meant ${this.idUser}?
Below code snippet worked for me:-
In component :
ngAfterViewChecked () {
if (this.elementRef.nativeElement.querySelector('ID or Class of the Html element')) {
this.elementRef.nativeElement.querySelector('ID or Class of the Html element').addEventListener('click', this.editToken.bind(this));
}
}
inside constructor parameter:-
constructor( private readonly elementRef: ElementRef) {}
import { ElementRef } from '#angular/core';---> at the top of the file
implement 'AfterViewChecked'
I want to navigate from one page to another and jump directly to one control in the middle of the destination page. Normally, we can use a hashtag "#" follow with the name or ID of the control.
However, this method does work that well in Angular 2. I have tried method like
Angular2 Routing with Hashtag to page anchor. With that method, the url does end with "#myId" but the page doesn't actually jump.
Do we have other ways to achive this?
Angular documentation project has AutoScrollService service. You can try to use it. auto-scroll.service.ts
/**
* A service that supports automatically scrolling elements into view
*/
#Injectable()
export class AutoScrollService {
constructor(
#Inject(DOCUMENT) private document: any,
private location: PlatformLocation) { }
/**
* Scroll to the element with id extracted from the current location hash fragment
* Scroll to top if no hash
* Don't scroll if hash not found
*/
scroll() {
const hash = this.getCurrentHash();
const element: HTMLElement = hash
? this.document.getElementById(hash)
: this.document.getElementById('top-of-page') || this.document.body;
if (element) {
element.scrollIntoView();
if (window && window.scrollBy) { window.scrollBy(0, -80); }
}
}
/**
* We can get the hash fragment from the `PlatformLocation` but
* it needs the `#` char removing from the front.
*/
private getCurrentHash() {
return this.location.hash.replace(/^#/, '');
}
}
$(document).ready(function() {
var apiRevoSlider = $('.tp-banner').show().revolution(
{
dottedOverlay:"none",
delay:9000,
startwidth:1140,
startheight:700,
hideThumbs:200,
thumbWidth:100,
thumbHeight:50,
thumbAmount:3,
navigationType:"none",
navigationArrows:"solo",
navigationStyle:"preview1",
touchenabled:"on",
onHoverStop:"on",
swipe_velocity: 0.7,
swipe_min_touches: 1,
swipe_max_touches: 1,
drag_block_vertical: false,
parallax:"mouse",
parallaxBgFreeze:"on",
parallaxLevels:[8,7,6,5,4,3,2,1],
parallaxDisableOnMobile:"on",
keyboardNavigation:"on",
navigationHAlign:"center",
navigationVAlign:"bottom",
navigationHOffset:0,
navigationVOffset:20,
soloArrowLeftHalign:"left",
soloArrowLeftValign:"center",
soloArrowLeftHOffset:20,
soloArrowLeftVOffset:0,
soloArrowRightHalign:"right",
soloArrowRightValign:"center",
soloArrowRightHOffset:20,
soloArrowRightVOffset:0,
shadow:0,
fullWidth:"off",
fullScreen:"on",
spinner:"spinner3",
stopLoop:"off",
stopAfterLoops:-1,
stopAtSlide:-1,
shuffle:"off",
forceFullWidth:"off",
fullScreenAlignForce:"off",
minFullScreenHeight:"400",
hideThumbsOnMobile:"off",
hideNavDelayOnMobile:1500,
hideBulletsOnMobile:"off",
hideArrowsOnMobile:"off",
hideThumbsUnderResolution:0,
hideSliderAtLimit:0,
hideCaptionAtLimit:0,
hideAllCaptionAtLilmit:0,
startWithSlide:0,
fullScreenOffsetContainer: ".header"
});
apiRevoSlider.bind("revolution.slide.onchange",function (e,data) {
if( $(window).width() > 992 ) {
if( $('#slider ul > li').eq(data.slideIndex-1).hasClass('light') ){
$('#header:not(.sticky-header)').addClass('light');
} else {
$('#header:not(.sticky-header)').removeClass('light');
}
MINOVATE.header.chooseLogo();
}
});
}); //ready
That may help you, btw if you had searched a bit you would have found it
/**
* Sample Directive
*/
define(['sampleLink', 'sampleCtrl'], function (link, controller) {
function sampleDir () {
return {
/**
* require is used by the link option
* can be a single controller, or an array. '^myController', or ['^controller2', '^controller1']
* controllers to be used in the link section. link (scope, element, attrs, requires)
*
* '^myController' - use ^ to search up the parents for the controller, otherwise it only looks at it's own element and will throw an error
* */
require : '',
/* restrict what type of elements this directive is rendered on E=element <directive> or A=attribute <element data-directive> */
restrict : 'EA',
/* *
* transclude in or outer scope. true = use the outer scope that this directive belongs to. false = create a scope inside the directive
* only use true when you want to create a directive that wraps arbitrary content
* when you use false and create a scope, you will want to pass in scope, or data through attributes on the element
* */
transclude : false,
/* *
* scope = create an isolate scope for the directive pass data into the directive through attributes
* This allows us to isolate the scope and reuse these directives throughout an app.
* =attr means to bind data to that attribute
* &attr means with transclude turned on this attribute will trigger evaluation of an expression in the context of the original scope
* any expression is allowed, including a function, this is ideal for binding callback functions to directive behaviors
* use this when we want the directive to expose an API for binding behaviors
* */
scope : {
inputObject : '=inputObject',
/*'close' : '&onClose'*/
},
/* templateUrl = Point to the template this directive should render */
templateUrl : '/a/tpl/modules/util/input/inputs.html',
/**
* link : use link when you want to manipulate the dom with the directive
* takes a function, inline or it can be dependency injected through requireJS
* use the following signature function lin k(scope, element, attrs) { ... }
*
* scope is an angular scope object
* element is the jqLite wrapped element that this directive matches
* attrs is a hash object with key-value pairs of normalized attribute names and their values
* */
link : link,
/**
* Specify a controller, and use controllerAs to alias the scope, if you want to reference the scope or it's functions in the template.
* You must define scope in the directive for this to be used.
*
* Q: What's the difference between controller and link? - A: Controllers can expose an API, and link can interact with controllers using require
*
* Best Practice: Only use controller when you want to expose the directive controller to another directive. Otherwise use Link
*
* This is great for building complicated directives that are made up of other directives and need to communicate with one another.
* */
controller : controller
/*controllerAs : 'input'*/
}
}
return sampleDir;
});
I wanted to add jsdoc annotations to my AngularJS codes, so i tried :
PageFactory.js
/**
* Creates an instance of PageFactory.
*
* #constructor
* #this {PageFactory}
*
*/
function PageFactory() {
}
angular.module ( 'app' ).factory ('PageFactory', PageFactory);
The above works fine and produces the expected jsdoc output. But when i enclose this codes in an anonymous function like this :
PageFactory.js
(function (){
/**
* Creates an instance of PageFactory.
*
* #constructor
* #this {PageFactory}
*
*/
function PageFactory() {
}
angular.module ( 'app' ).factory ('PageFactory', PageFactory);
})();
The generated jsdoc html output is blank and no documentation on PageFactory class.
Is theres a way to make jsdoc work with anonymous functions or to work with my second code?
Thanks in advance.
Use #lends <global> like this:
(/** #lends <global> */ function (){
// etc... the rest remains the same.
Say I have a DOM that looks like this in my Document:
<body>
<div id="outer">
<custom-web-component>
#shadow-root (open)
<div id="inner">Select Me</div>
</custom-web-component>
</div>
</body>
Is it possible to select the inner div inside the shadow root using a single querySelector argument on document? If so, how is it constructed?
For example, something like document.querySelector('custom-web-component > #inner')
You can do it like this:
document.querySelector("custom-web-component").shadowRoot.querySelector("#inner")
In short, not quite. The TL:DR is that, depending on how the component is set up, you might be able to do something like this:
document.querySelector('custom-web-component').div.innerHTML = 'Hello world!';
Do do this - if you have access to where the web component is created, you can add an interface there to access inner content. You can do this the same way you would make any JavaScript class variable/method public. Something like:
/**
* Example web component
*/
class MyComponent extends HTMLElement {
constructor() {
super();
// Create shadow DOM
this._shadowRoot = this.attachShadow({mode: 'open'});
// Create mock div - this will be directly accessible from outside the component
this.div = document.createElement('div');
// And this span will not
let span = document.createElement('span');
// Append div and span to shadowRoot
this._shadowRoot.appendChild(span);
this._shadowRoot.appendChild(this.div);
}
}
// Register component
window.customElements.define('custom-web-component', MyComponent);
// You can now access the component 'div' from outside of a web component, like so:
(function() {
let component = document.querySelector('custom-web-component');
// Edit div
component.div.innerHTML = 'EDITED';
// Edit span
component._shadowRoot.querySelector('span').innerHTML = 'EDITED 2';
})();
<custom-web-component></custom-web-component>
In this instance, you can access the div from outside of the component, but the span is not accessible.
To add: As web components are encapsulated, I don't think you can otherwise select internal parts of the component - you have to explicitly set a way of selecting them using this, as above.
EDIT:
Saying that, if you know what the shadow root key is, you can do this: component._shadowRoot.querySelector() (added to demo above). But then that is quite a weird thing to do, as it sorta goes against the idea of encapsulation.
EDIT 2
The above method will only work is the shadow root is set using the this keyword. If the shadow root is set as let shadowRoot = this.attachShadow({mode: 'open'}) then I don't think you will be able to search for the span - may be wrong there though.
This code will behave like query selector and work on nested shadowDoms:
const querySelectorAll = (node,selector) => {
const nodes = [...node.querySelectorAll(selector)],
nodeIterator = document.createNodeIterator(node, Node.ELEMENT_NODE);
let currentNode;
while (currentNode = nodeIterator.nextNode()) {
if(currentNode.shadowRoot) {
nodes.push(...querySelectorAll(currentNode.shadowRoot,selector));
}
}
return nodes;
}