I am having what seems to be a common issue with Polymer 1.0: accessing nodes inside a dom-if template, but none of the proposed solutions seem to work in my case (?!)..
Here is a simple example:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="my-test">
<template>
<div>
<template is="dom-if" if="{{show}}" id="tplId">
<p id="message">hello</p>
</template>
</div>
<a on-tap="tapEvent">click me!</a>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'my-test',
show: false,
ready: function() {
},
tapEvent: function() {
// show the template
this.show = true;
// How may I access #message since the template is inhert ?
// this finds the template by id
console.log(Polymer.dom(tplId));
// this won't find the #message element inside it
console.log(Polymer.dom(tplId).querySelector('#message'))
// this neither
console.log(Polymer.dom(this.root).querySelector('#message'))
// this neither
console.log(Polymer.dom(this).querySelector('#message'))
// this neither .. Should I even be using this.shadowRoot in 1.0?
console.log(Polymer.dom(this.shadowRoot).querySelector('#message'))
// this neither
console.log(this.$$('#message'))
// this cannot work because #message is not a statically created DOM element
console.log(this.$.message)
}
});
})();
</script>
</dom-module>
I'm new to Polymer, and I feel the solution might be right under my nose..?
If this
// this neither
console.log(this.$$('#message'))
doesn't work then you probably try to query the element while it doesn't exist. When show is false the <p id="message"> element doesn't exist at all. If you need this then bind to hidden instead of using dom-if
<p id="message" hidden$="{{show}}">hello</p>
then
console.log(this.$.message);
will work as well.
Related
I created a component and I am trying to make the component's template dynamic, that is, for some condition the parent tag should be a div, otherwise it should be an anchor tag.
I have been trying to use ng-if but somehow it wont work. Here is a code snippet. For some reason, even if the ng-if is true, the nested div (.testDiv .testThumbnail) will be undefined and this will break my component.
I cannot understand why it doesn't find the component even if the ng-if is true. I am new to Angular JS, so maybe I am missing something here? Or there is a better way to dynamically create the component's parent tags according to some condition.
function myCardController($window) {
var element = angular.element(document.querySelector('.testDiv .testThumbnail'));//is undefined
}
angular.module('myApp').component('myCard', {
templateUrl: 'testTemplate', ,
controller: ["$window", myCardController],
});
<script type="text/ng-template" id="testTemplate">
<div ng-if="true"
class="testDiv">
<div role="img" class="testThumbnail"></div>
</div>
<a ng-if="false" class="tesstDiv">same content</a>
</script>
You probably miss to add ng-app or ng-controller directive. Use following HTML as your template:
<div ng-controller = "myCardController">
<div ng-if="show"
class="testDiv">
<div role="img" class="testThumbnail"></div>
</div>
<a ng-if="!show" class="tesstDiv">same content</a>
</div>
Update your JS code as like:
function myCardController($window) {
var element = angular.element(document.querySelector('.testDiv .testThumbnail'));//is undefined
$scope.show = true;
}
angular.module('myApp').component('myCard', {
templateUrl: 'testTemplate.html', ,
controller: ["$window", myCardController],
});
You also can use ng-app="myApp" in your body tag.
I am trying to have certain content of a polymer element procedurally added, at a time later than its creation. I am trying to avoid a <template is="dom-if"> element.
Instead I am trying to have a nested <template> element inside the polymer element's template and have its content attached on the execution of a method, like so:
<dom-module id="simple-element">
<template>
<content id="content"></content>
<div id="display">display</div>
<template id="t">
template content
<script>console.log("template added!")</script>
</template>
</template>
<script>
var simpleElement = {
is: "simple-element",
attached : function(){
this.init();
},
init : function(){
var t = document.importNode(this.$.t.content,true);
this.$.display.appendChild(t);
},
}
Polymer(simpleElement);
</script>
</dom-module>
See it also in this jsbin http://jsbin.com/zudituvuli/edit?html,js,console,output
Is there a way to accomplish this?
I have a polymer component defined as below:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="add-money">
<template>
<style></style>
<paper-dialog id="add-money-dialog" modal >
<h2>Add money</h2>
<paper-dialog-scrollable>
<div>
<span>{{account.name}}</span>
</div>
</paper-dialog-scrollable>
<div class="buttons">
<paper-button dialog-dismiss>Cancel</paper-button>
<paper-button dialog-confirm autofocus>Add</paper-button>
</div>
</paper-dialog>
</template>
<script>
var AddMoney = Polymer({
is: 'add-money',
properties: {
account: {
type: Object,
notify: true,
}
},
factoryImpl: function(acc) {
this.account=acc;
},
showPopup:function(){
console.log(JSON.stringify(this.account));
var dialog = document.getElementById("add-money-dialog");
if (dialog) {
dialog.open();
}
}
});
</script>
</dom-module>
Now, I instantiates it and add to body on click of a button from another component.
addMoney:function(e){
var button = e.target;
var dialog = new AddMoney(e.model.item);
document.body.appendChild(dialog);
dialog.showPopup();
}
While doing that, I am able to see that data available in showPopup method, but the same does not reflect on the DOM.
Curious, what could be the problem and what is the fix for it. I am a newbee to this and trying to write some component based code to understand polymer. Please advice on this. Thanks in advance.
It was infact an issue with the styles. I thought the value is not coming up since there was nothing displayed. But it was actually hidden and I could not see it. I added some styles ot the paper-dialog-scrollable and now I can see the values.
I'm using Kendo UI version 2014.2.716 with AngularJS version 1.2.27, and I made a grid using a directive
<div ng-controller="MyController as ctrl">
<div id="myGrid" kendo-grid k-options="{some options}"></div>
<button ng-click="ctrl.doSomething()"></div>
</div>
I read that if you give a name to the grid (like this: kendo-grid="myGridOnScope"), you can access the widget in the controller scope in this way:
myModule.controller('MyController', function($scope) {
this.doSomething = function() {
console.log($scope.myGridOnScope);
}
}
The console.log should log a widget object, but in my case it's undefined. What am I doing wrong? Thanks for the help
I have found out the problem myself, so I'm going to post an answer if someone has the same problem. If you use the controllerAs syntax in AngularJS, you can't just write the name of the widget - you have to prefix it with your controller alias.
Take a look at this example:
<div ng-controller="MyController as ctrl">
<div kendo-grid="myGridName"></div>
</div>
This will not give you the grid object on the $scope - for that you need to add the ctrl prefix:
<div ng-controller="MyController as ctrl">
<div kendo-grid="ctrl.myGridName"></div>
</div>
Now you have access to the widget in your controller like this:
angular.module('MyModule',['kendo.directives'])
.controller('MyController', function($scope){
// this gives you the widget object
console.log(this.myGridName);
// however, this doesn't work
console.log($scope.myGridName);
});
I hope I helped someone with this post.
Cheers,
Try waiting for the event that Kendo emits.
Html
<div kendo-grid="grid" options="gridOptions"></div>
Javascript
$scope.$on("kendoWidgetCreated", function(event, widget){
if (widget === $scope.grid) {
console.log($scope.grid);
}
});
Edit: See this Plunker
It is because angular is too fast and the kendo element doesn't exist when you try to set the options.
I solved this with a watch.
This is my html code:
<div kendo-grid="ListDesign"></div>
And this is my angular code
$scope.$watch('ListDesign', function () {
if ($scope.ListDesign != undefined) {
var gridOptions = {
columns: columns,
sortable: {
mode: 'multiple',
allowUnsort: true
}
};
$scope.ListDesign.setOptions(gridOptions);
$scope.ListDesign.setDataSource(dataSource);
}
});
Does this answer your question?
I need to use angular and masonry and also implement sorting and filtering.
The fiddle here does use the masonry with Angular and has filtering and sorting working, however the layout does not seem like masonry. I do not think the masonry layout is applied at all.
http://jsfiddle.net/rdikshit/6swek/3/
<div ng-app="test">
<div ng-controller="MainCtrl">
<input type="text" ng-model="nameFilter" />
Order by id
Order by name
Order by age
<div class="items" masonry >
<div ng-repeat="item in items | filter: { name: nameFilter } | orderBy: order:reverse" class={{item.style}}>
<span>{{item.name}}</span>
<span>id: {{item.id}}</span>
<br /> <span>Age: {{item.age}}</span>
<br /> <span>Style: {{item.style}}</span>
</div>
</div>
</div>
</div>
Here is another fiddle with Passy's directive:
http://jsfiddle.net/rdikshit/6swek/5/
STill does nt work. Even the sorting and filtering are not working now.
I modified your JSFiddle and got it to work. Since columnWidth is not specified, the width of the first element is used. That's why there is gap between the elements sometimes
Few points to look out for:
Don't save the Masonry instance, since you are using the JQuery version. To access Masonry methods, simply get the container element then do container.masonry( 'methodName', arguments );
The watches in the controller are not ideal, in a real app you probably want to put them into a directive
The technique where you watch the number of children in the Masonry container doesn't work when you have ngAnimate as one of your dependency. It cause the DOM tree to be updated after $digest(), which make $watch miss
I am working on a simular project, but i am using Isotope with a mansory style.
here is the way i am using it:
Directive:
app.directive('isotope', function ($timeout) {
return {
scope: {
items: '=isotope'
},
templateUrl: 'social-item.html',
link: function (scope, element, attrs) {
var options = {
animationEngine : 'jquery',
itemSelector: '.social-item',
layoutMode: 'masonry',
masonry : {
"gutter": 10,
"isFitWidth": true
}
};
element.isotope(options);
scope.$watch('items', function() {
$timeout(function() {
element.isotope( 'reloadItems' ).isotope();
});
},true);
}
};
});
Directive template (social-item.html):
<div class="social-item" ng-repeat="item in items track by $index">
<!--
Do something with item, in your case something like this:
<span>{{item.name}}</span>
<span>id: {{item.id}}</span>
-->
</div>
HTML Markup:
<div class="social-wall-container" isotope="socials.posts">
<!-- repeat posts from directive -->
</div>
For more information about isotope checkout This link
If you decide to use isotope, make sure to include the necesary files located in the JS folder on the github page.