Dart + Polymer + google_maps - google-maps

I'm trying to write a polymer element in charge of draw a google maps representation.
This is the code:
#CustomTag('map-element')
class MapElement extends PolymerElement {
...
#override
void attached() {
super.attached();
canvasMap = $['canvas_map'];
initMap();
window.navigator.geolocation.watchPosition(enableHighAccuracy: true)
.listen(
(Geoposition position) {addPosition(position);},
onError: (error) => handleError(error));
}
...
void initMap(){
gmap = new GMap(
canvasMap,
new MapOptions()
..zoom = 4
..center = new LatLng(0, 0)
..mapTypeId = MapTypeId.ROADMAP
);
line = new Polyline(
new PolylineOptions ()
..map = gmap
..strokeColor='#0022ee'
..geodesic=true
..strokeOpacity=0.7
..strokeWeight=2
..visible=true);
}
}
And this is the exception thrown when I try to create an instance of GMap:
Class 'GElement' has no instance method '[]'.
NoSuchMethodError: method not found: '[]'
Receiver: Instance of 'GElement'
Arguments: ["maps"]
I think the problem is because polymer uses DOM shadow, do you know any workaround?
Here is the whole project: https://github.com/carlosvin/snowroute
Now it is working, here you can try it: http://carlosvin.github.io/snowroute/
I have added javascript tag only in index.html, not in polymer element declaration.
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
My try is in https://github.com/carlosvin/snowroute , the relevant files for this question are: web/map_element.dart, web/map_element.html and web/index.html.

Simple, you're just missing the JavaScript tag
<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
I also tried to do what you're doing and forgot to include this, and got the same error. I found you can include it here
<polymer-element name="map-element">
<template>
<div id="canvas_map"></div>
</template>
<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="application/dart" src="map_element.dart"></script>
</polymer-element>
Or you can include it in the main index.html file.
Though this doesn't implement the CSS you must apply to actually size and see the map, that's another question, one which I've already answered here How to use javascript from Dart inside a polymer element.

Related

Polymer: calling a dynamic custom element's method from another script

i'm trying to call a dynamic custom element's method. It works only when the call is made inside the script tag of the custom element's html file. But when call is made in another custom element's script tag or in the script tag of index.html, i get the error: 'method-name' not a function in the console. Thanks for your response. for context, here is a snippet
// in my custom element html file
....
<script type="text/javascript">
Polymer( {
is: "my-new-view",
toggleContent: function() {
this.$.collapse.toggle();
},
insertContent: function (userContent) {
console.log("inserting userContent...");
}
});
</script>
</dom-module>
</html>
Now in another file my-app.html
...
<link rel="import" href="my-new-view.html">
...
<dom-module is="my-app">
...
<script>
...
// i want to test my-new-view. insertContent() here.
var dynamicView = document.createElement('my-new-view');
// in the following line i get the error insertContent is
// not a function
dynamicView.insertContent();
</script>
</dom-module>
pls help. what am i doing wrong. i tried the last 2 lines of javascript in my index.html as well but i get the same error. Thanks.

I think that maybe you're trying to call that method too early, when the elements have not been registered yet.
In index.html you can wrap you code in handler of WebComponentsReady event
window.addEventListener('WebComponentsReady', function(e) {
document.createElement('my-new-view').insertContent();
});
In other Polymer elements you could move your code inside of the my-app element rather than directly in the script.
Also, to check whether a custom element is available I look at document.createElement('my-new-view').constructor. If it says function HTMLElement() { [native code] } (in Chrome), it means that it's not available (usually an import is missing).

Polymer 1.0: <iron-meta> usage

Proper usage of the Polymer 1.0 element <iron-meta> is confusing. Here is the link on Github. And here is the link to the Polymer demo site.
Can someone please provide a proper code example of how to make it work?
This is the code I have so far.
<dom-module id="generic-element">
<style>...</style>
<template>
<iron-meta id="meta" key="info" value="foo/bar"></iron-meta>
The <code>value</code> stored at <code>key="info"</code> is <code><span>{{test}}</span></code>.
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'generic-element',
properties: {
test: {
value: function(){
return "Hello world"; // This is the only thing I can get to work so far.
// return (new Polymer.IronMetaQuery({key: 'info'}).value); // Doesn't totally break.
// All my other below attempts totally fail. Everything breaks.
// return this.$.meta.IronMetaQuery({key: 'info'}).value;
// return this.IronMetaQuery({key: 'info'}).value;
// return this.$.meta.byKey('info').getAttribute('value');
// return this.$.meta.byKey('info').value;
}
}
}
});
})();
</script>
Here is the Github link to the issue. And here is a Github repository that contains the complete problem code in context of the complete web app.
The issue with your code is that you are trying to set your element property's default value to something that's declared inside that same element's template itself. Two of the things that happen between the time when the element is created and when that element is attached include a) properties' default values are set; and b) the template undergoes preparations to be stamped into DOM. These tasks happen asynchronously so in essence you are generating a race condition.
Try setting your test default value inside the ready() callback - the ready() callback guarantees that DOM is ready to be accessed, which in your case is exactly where you declared your <iron-meta> key.
<dom-module id="generic-element">
<style>...</style>
<template>
<iron-meta id="meta" key="info" value="foo/bar"></iron-meta>
The <code>value</code> stored at <code>key="info"</code> is <code><span>{{test}}</span></code>.
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'generic-element',
properties: {
test: String
},
ready: function () {
// this will work
this.test = this.$.meta.byKey("info");
}
});
})();
</script>
jsbin: http://jsbin.com/vosekiwehu/edit?html,output

Knockout binding from a JSON data string

I'm currently using Knockout to render my HTML page, but I'm stuck when I'm trying to render my HTML when the data is stored in a simple JSON file.
The Json file is here:
{
"name": "Office Web Controls 2014"
}
Here's the function to load my Json string:
<script type="text/javascript">
function AppViewModel() {
this.data = { };
$.getJSON("Resources/Data/Ribbon.json", function(retrievedData) {
this.data = ko.mapping.fromJSON(retrievedData);
console.log(this.data);
});
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
</script>
And I would like to bind it to the following HTML:
<div data-bind="text: data.name">
</div>
I've tried very different things but none are working, so if anybody has an idea on how to accomplish this.
Finally, after a long search, I've managed to find the solution.
For anyone who's intrested, here it is:
<div data-bind="template: {name: 'OfficeWebControls-Title', data: ribbonViewModel}">
</div>
And finally the script:
<script type="text/javascript">
var ribbonViewModel;
$.getJSON("Resources/Data/Ribbon.json", function(data) {
ribbonViewModel = ko.mapping.fromJS(data);
ko.applyBindings(ribbonViewModel);
});
</script>
The reason it wasn't working is two fold:
The this pointer in the call back function is not pointing to your vm
Resources:
jQuery/JavaScript "this" pointer confusion
How does the "this" keyword work?
The data property of your vm needs to be converted to an observable
The $.getJSON call will execute asynchronously and the response will be handled after the ko.applyBindings call. This means that you'll be changing the value of the data property after it's bound to the UI. For the UI to receive changes after it is bound the properties on the view model will need to be wrapped in observables.
Example
function AppViewModel() {
//remember the this pointer for the call back handler
var self = this;
//set default data to an observable
self.data = ko.observable(null);
$.getJSON("Resources/Data/Ribbon.json", function(retrievedData) {
//use self to reference properties on the vm in a call back handler
self.data(retrievedData);
console.log(self.data());
});
}
ko.applyBindings(new AppViewModel());
For this to work the view will also need to change.
<!-- ko if:data -->
<div data-bind="text: data().name"></div>
<!-- /ko -->
fiddle

Is it possible to share mixins across web components (and imports) in Polymer?

As a follow up to How to extend multiple elements with Polymer and Polymer multiple inheritence/composition, based on their answers, I wonder if it's possible to share mixins across multiple web components (and multiple imports) to reuse functionality.
Mixins seem to be the only way to share functionality across multiple custom elements. However, it seems like you can only use a mixin within one import. Which means, if you have a mixin, that gives a web component a specific functionality (let's say draggable), it's not possible to mix it into the construction of your Polymer element if it's not in the same import.
Maybe I got something wrong there but if not, it feels like that the use of mixins isn't very flexible either, because I'm still not able to share functionality across web components.
UPDATE:
As Scott Miles pointed in his comments out, it is possible to use mixins in more than one import. I just wasn't sure how to do that and it turns out, that it's very straight forward.
Let's say we have a mixin that should be shared across multiple components, but components are distributed over many imports. All one has to do is to define that mixin in its own import on the window object. So for example:
shared.html
<script>
window.sharedMixin = {
// shared functionality goes here
};
</script>
And then, reusing that mixin in another component in another import, is as simple as importing shared.html.
my-component.html
<link rel="import" href="path/to/shared.html">
From that point on, sharedMixin is available as global object within that import:
Polymer('my-component', Platform.mixin({
// my-component logic
}, sharedMixin);
I hope that helps others. I'll write a blog post about that and will link it here.
UPDATE 2
I've written a blog post here: http://pascalprecht.github.io/2014/07/14/inheritance-and-composition-with-polymer/
To use a global-like component is the recommended way to go.
make a <name-you-like> and use get/set to change it (also you can use attributes although they are only sad strings).
from Polymer API guide you'll see working (good looking) examples like this:
<polymer-element name="app-globals">
<script>
(function() {
// these variables are shared by all instances of app-globals
var firstName = 'John';
var lastName = 'Smith';
Polymer({
ready: function() {
// copy global values into instance properties
this.firstName = firstName;
this.lastName = lastName;
}
});
})();
</script>
</polymer-element>
And play with them using javascript es5 getters/setters such as in the above mentioned case would look like
<polymer-element name="app-globals">
<script>
(function() {
// these variables are shared by all instances of app-globals
var firstName = 'Arnold';
var lastName = 'Schwarzenegger';
Polymer({
ready: function() {
// copy global values into instance properties
this.firstName = firstName;
this.lastName = lastName;
},
get fullTerminatorName() {
return this.firstName + ' ' + this.lastName;
}
});
})();
</script>
</polymer-element>
I'll be back.
This is now addressed by the Behaviors feature.
Example:
my-behavior.html:
<script>
MyBehavior = {
properties: {},
listeners: [],
_myPrivateMethod: function(){}
// etc.
};
</script>
my-element.html:
<link rel="import" href="my-behavior.html">
<script>
Polymer({
is: 'my-element',
behaviors: [MyBehavior]
});
</script>
my-other-element.html:
<link rel="import" href="my-behavior.html">
<script>
Polymer({
is: 'my-other-element',
behaviors: [MyBehavior]
});
</script>

Constructor syntax in Mootools, Arguments for container (noob)

Sorry for this absolute noob question.
I am trying to implement Tabs with this MooTools Plugin:
http://mootools.net/forge/p/simple_tab_pane
The syntax for the constructor is as follows:
var myTabPane = new TabPane('tabs', {
tabSelector: 'li',
contentSelector: 'p'
});
Where 'tabs' is the CSS-id of the container.
Now I would prefer to use a class for the container but '.tabs' won't work.
What would be the correct syntax for this?
And how should i do it to adress for example every div-Element ?
well first things first - what is expected:
https://github.com/akaIDIOT/MooTools-TabPane/blob/master/Source/TabPane.js#L44
he expects argument to be an element id or an actual element. how you arrive to that element is up to you.
var myTabPane = new TabPane(document.getElement('.tabs'), {
tabSelector: 'li',
contentSelector: 'p'
});
passing an element found based upon a class search for .tabs.
alternatively, you can re-implement the initialize method on the class and write the line as:
this.container = document.getElement(container);
this.container.getElements(this.options.contentSelector).setStyle('display', 'none');
so you can then pass a jquery like selector: new TabPane('#someid') or new TabPane('div.someclass')
You'd refactor it by doing TabPane.implement({ initialize: fn(){... }) or do a subclass like var myTabs = new Class({extends: TabPane, initialize: fn(){ ... }). When you extend, this.parent() will call the parent method over the prototype.