How to know google map controls creation is done? - google-maps

I need to dynamically create a ui widget with a parent div.id='myDivId', which is a google map control.
var centerControlDiv = document.createElement('div');
var centerControl = new CenterControl(centerControlDiv, map);
centerControlDiv.index = 1;
centerControlDiv.id = 'myDivId';
map.controls[google.maps.ControlPosition.TOP_CENTER].push(centerControlDiv);
// $('#myDivId') causes exception as $('#myDivId') is not created on
// map as a DOM element yet.
var uiWidget = new uiWidget('myDivId');
// $(#myDivId) is used in class uiWidget().
class uiWidget {
constructor(divId) {
this.id = divId;
// It should fail here due to this.$div property, as
// div 'myDivId' is not a DOM element yet by google map
// controls API.
this.$div.click($.proxy(this.event_click, this));
}
get $div() {
return $(‘#’ + this.id);
}
event_click(eve) {
}
}
But, there is no event of when this parent div is created. Therefore, the child ui widget can't be created at correct time.
How to know parent div with id 'myDivId' is created?

You are trying to reference a DOM element by ID as a child of document when that element has only been created but not yet added to the document.
But you already have a reference to the #myDivId element in the centerControlDiv variable, so you don't need to use the ID to reference it. Just change this line:
$('#myDivId').append("<div>UI widget</div>");
to:
$(centerControlDiv).append("<div>UI widget</div>");
Put another way, to answer your question "How to know parent div with id 'myDivId' is created?", that div already is created - you created it in the document.createElement('div') call. It just isn't a child of document yet.
So when you use $('#myDivId'), or similar calls like document.getElementById('myDivId'), those calls can't see it. It's just a standalone element that you have a reference to, so you can access it through that element instead of looking it up in the document DOM.
Update based on your latest code:
To apply this principle to your uiWidget class, you can have the class work with the actual div element you created instead of accessing it by ID. Even better, since you're using jQuery, pass it a jQuery object from the beginning, like this:
var uiWidget = new UiWidget( $(centerControlDiv) );
class UiWidget {
constructor($div) {
this.$div = $div;
this.$div.click($.proxy(this.event_click, this));
}
// ...
}
As you can see, the code no longer requires the div ID at all, and it doesn't need the get $div() either. $div and this.$div are already a jQuery object wrapping your centerControlDiv.
I also changed the name of the class to UiWidget to follow recommended JavaScript style and avoid conflict with the uiWidget variable that holds an instance of the class.

Related

Polymer - Fire not updating the UI checkboxes

I have very simple setup. When I check on checkbox, a pop up will open and ask to link to another checkbox.
When I close the popup, whatever the checkbox I selected, both will be checked.
I have array updated with checkbox value.
After I close the popup, the values are showing right in the array but not in UI. When I select other tab and get back to this tab, checkboxes are showing right.
this.fire('details', this.details);
This is not working from child page.
How can I refresh the parent element?
Above your details event, will fire an event with on-<your-custom-event> at parent element as on-details So you need to assign a listener something like at parent:
<child-element
on-details = '_detailsChanged'>
</child-element>
...
Polymer {(
_detailsChanged: function(e) {
// e.detail will give you this.details object
}
Or I assume you want to assign an object at the child and reflect observations on the parent, so at parent element :
<child-element
details = "{{details}}"
><child-element>
and at the child element, you need to notify=true this object at property declarations and notifyPath with making observable changes at parent something like:
properties: {
details: {
type:Object,
notify:true
}
}
..
this.set('details', nevDetailsValue); //Use this.set method
this.notifyPath('details'); // Than detail property will change value at parent.
EDIT : Need to specify the exact path !!
DEMO
this.notifyPath('details.<path which is changed>'); // ie:this.notifyPath('details.name')

Add API to Polymer web component

I am building a Polymer web component that should respond to mouse/touch events. I would like to bind the on-tap="{{$.myElement.show}}" where show is a function in the element:
show: function(e) {
// Do something with the event here
}
Is there anyway to define a public API in Polymer. The route I am going at the moment is to have attributes="event" on the element then the parent element has on-tap="{{updateEvent}}":
updateEvent: function(e) {
this.$.myElement.event = e;
}
The element then just has:
eventChanged: function() {
show(this.event);
}
Which just seems boilerplaty (think that is a made up word). Can I add the show function to the element prototype somehow?
If show() is a method on your element, just use on-tap="{{show}}". show() is part of the element's public APi.
But it looks like you want is to call another element's method? This came up recently in a pull request: https://github.com/Polymer/polymer-dev/pull/30
What you have with setting this.$.myElement.event = e; and using eventChanged() in myElement works. You can also just call the element's method directly:
updateEvent: function(e) {
this.$.myElement.show();
}
Here are a few other ways: http://jsbin.com/guyiritu/1/edit

Adding an object reference to a component from the properties window

Is there a way to pass an object reference to a component directly from the property/component parameter window? Using the [Inspectible] tag only allows me to input strings and not actual object references.
For example, I have a custom component called "knob" which should hold a reference to a door on the stage which it opens. I know this can be easily done in code with "knob.door = someDoor;" but since there are many objects in the scene I would prefer if I could do it visually trough the properties window.
I don't think you can do this. Your best bet is to pass in a string identifier (perhaps a whole dot-separated path if your clips are deeply nested), and then implement code inside your custom component to find that item by name.
I've got a custom component which lays itself out relative to horizontal and vertical predecessor components, so I do this:
protected var horizontalPredecessor:String = "";
[Inspectable(name = "HorizontalPredecessor", type = String, defaultValue="")]
public function set HorizontalPredecessor($value:String):void
{
horizontalPredecessor = $value;
drawNow();
}
override protected function draw():void
{
if (parent)
{
if (horizontalPredecessor != "")
{
var hp:DisplayObject = parent.getChildByName(horizontalPredecessor);
if (hp)
{
x = hp.y + hp.height + horizontalSpacing;
}
}
}
}
... which is made easy because all these components share the same parent.
Alternatively, if there's only one door, you could make it a singleton, and give it a static reference, like this:
public class Door
{
private static var _singleton:Door;
public static function get Singleton():Door
{
if(!_door) _door = new Door();
return _door;
}
}
Then your handle can just refer to Door.Singleton and you don't have to worry about passing anything in. Alternatively, you could have a static array of Doors in the Door class, and give your handle an index number to link it to a specific Door.

checking if child exists

Hello i have a function as following:
private function seatClickHandler(e:MouseEvent):void{
var check:Check = new Check();
if(e.target.contains(check)){
e.target.removeChild(seat);
}else{
e.target.addChild(check);
}
}
basicly i want to check if e.target contains a child called check. If it does i want e.target to remove the child, else i want to add the child. But the method i tried doesnt seem to work although i think this is the way to go. Any suggestions?
When you declare your Check object, Actionscript creates a reference code for that specific object.
So the first time your code is run, your Check object could be given a reference of #c0ecc29. Your if statement checks to see if #c0ecc29 is a child component of target. It won't be, so the Check object with reference #c0ecc29 is added to target.
The second time the clickHandler is called, a new instance of the Check object is created which will have a new reference id. Your target has the original Check object with the #c0ecc29 reference so it won't get removed.
The correct way to get this working depends on what target is (DataGrid, Group, etc.).
EDIT:
Based on your comments, I would try something like this. It checks to see if the Check object is a child of target and adds it if needed. Then when the Check object is clicked, it will toggle its visibility.
public var check:Check = new Check();
private function seatClickHandler(e:MouseEvent):void
{
if(!e.target.contains(check))
{
check.addEventListener(MouseEvent.CLICK, check_handleClick);
e.target.addChild(check);
}
}
protected function check_handleClick(event:MouseEvent):void
{
check.visible = !check.visible;
}
If you need to actually remove the Check object from target instead of just changing its visibility, you could try this:
public var check:Check = new Check();
private function seatClickHandler(e:MouseEvent):void
{
if(!e.target.contains(check))
{
e.target.addChild(check);
}
else
{
e.target.removeChild(check);
}
}
If the child is named 'check' then you should be able to use getChildByName(). See flash.display.DisplayObject.name
If you happen to have the child in memory, you can use getChildIndex()
check is a new object in the scope of that function, so it will not be a child of the event target.
What you want to do is declare check as a global variable (And also cast target as DisplayObjectContainer).
e.g.
private function seatClickHandler(e:MouseEvent):void{
if((e.target as DisplayObjectContainer).contains(check)){
(e.target as DisplayObjectContainer).removeChild(seat);
}else{
(e.target as DisplayObjectContainer).addChild(check);
}
}
However I'm not sure if this is exactly what you want to do (There can only be one check). A better approach would be to have a function (maybe toggleCheck) on the target, and have that display object responsible for rendering the check (And removing it)
This worked perfectly fine for me in my situation:
if(possibleChild.parent == holder)
holder.removeChild(possibleChild)
It may or may not be exactly what you're looking for.

How to insert a g:text object inside another html element?

I'm developing a Windows gadget. There is a function called addTextObject on the background object which creates the object I want which I can later add glowing and shadows to it. But the problem is that I am not able to control the objects location. For example, if I want to append it inside a div or span or td, the appendChild method is not working. How can I fix this?
var txtGlow = document.getElementById('imgBackground').addTextObject("test", "Verdana", 25, "Red", 50, 50);
txtGlow.opacity = 100;
txtGlow.addGlow("yellow", 50, 50);
var theDiv = document.getElementById('divx');
txtGlow.value = theDiv.innerText;
theDiv.appendChild(txtGlow);
Text and image objects added to the background aren't elements and as such can't be appended to just any element. You can create a <g:text> element in your HTML markup, but they don't behave in the same way:
Note This method does not expose the objects as g:image or g:text elements. You can locate and assign the objects using the document.getElementById("...") method, but the g:image or g:text methods and properties are not available.
You could create the element using document.createElement() or innerHTML.