What is the best way to dynamically change contentEl? I can see update method, but it works with string/template input, and I can still use it to reset content using somehow innerHTML. But what about resetting DOM element itself?
var divA = document.createElement("div");
divA.innerHTML = "divA";
var divB = document.createElement("div");
divB.innerHTML = "divB";
var win = Ext.create('Ext.window.Window', {
title: 'An Example',
height: 200,
width: 400,
layout: 'fit',
contentEl: divA
}).show();
window.setTimeout(function() {
//this will work, but what about DOM?
var buf = document.createElement('div');
buf.appendChild(divB);
win.update(buf.innerHTML);
}, 2000)
You may use the replaceWith() method, along with the config object for the new element to create:
Ext.get(contentEl).replaceWith({ html: '<div>hello, world</div>' });
Related
I have custom control inside TabPanel: {items: Panel: {items: customcontrol}}.
Inside control, i create dynamically in onRender handler image control with picture. Picture can be different sizes. How me refresh current container, that it took the right size? It happen automatically, then i switch to another tab and back. doLayout() not working, function updateLayout() violates the layout of the other tabs.
creating image:
onRender: function () {
var me = this;
me.callParent(arguments);
this.el.update(this.imageFieldTpl.apply(this));
var imageWrap = Ext.query('.image-ct', this.el.dom)[0];
this['image'] = Ext.create(Ext.Img, {
name: 'image',
height: "100%",
width: "100%",
renderTo: imageWrap
});
if (this.value != null) {
this.fireEvent('imageChange', this.value);
}
}
I'm going crazy here trying o work out why the scoping of my variable won't pick up the right value from a loop of 60 items from a DB in my Appcelerator project.
My map marker displays the correct label, but when I click it, no matter what combo of scoping I try, I cannot get the correct value in the alert. It just returns the 60th entry every time.
Likely a schoolboy error, but this is driving me nuts.
This is my function
function loadAnimals() {
var db = Ti.Database.open('myDB');
var getSpecies = db.execute('select * from species');
while (getSpecies.isValidRow()) {
var speciesID = getSpecies.fieldByName('speciesnid');
var speciesName = getSpecies.fieldByName('speciesname');
var speciesDesc = getSpecies.fieldByName('speciesdescription');
var speciesLatitude = getSpecies.fieldByName('specieslatitude');
var speciesLongitude = getSpecies.fieldByName('specieslongitude');
var speciesConStatus = getSpecies.fieldByName('speciesconservationstatus');
var speciesMarkerFilename = getSpecies.fieldByName('speciesiconfilename');
var speciesMarkerIcon = getSpecies.fieldByName('speciesmapicon');
var speciesMarkerURI = getSpecies.fieldByName('speciesmapiconurl');
var speciesImageFullPath = speciesMarkerURI.replace("public://", "http://myurl.com/");
var speciesImageFullPath = speciesImageFullPath.replace(" ", "%20");
var imageFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, speciesMarkerIcon);
var iconFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, speciesMarkerFilename);
var annotationView = Ti.UI.createView({
backgroundColor: '#222222',
width: 150,
height: 75,
layout:'vertical'
});
var addtoTourView = Ti.UI.createView({
height:20,
backgroundColor:'#6ea108'
});
var addtoTourTitle = Ti.UI.createLabel({
color: '#FFF',
text: 'ADD TO TOUR',
width: 150,
height: 15,
top:3,
textAlign: 'center',
font: {
fontSize: 14,
fontWeight: 'bold'
}
});
var annotationTitle = Ti.UI.createLabel({
color: '#FFF',
text: 'test',
width: 150,
height:15,
top:0,
textAlign: 'center',
font: {
fontSize: 14,
fontWeight: 'normal'
}
});
var blankView = Ti.UI.createView({
backgroundColor: '#222222',
width: 1,
height: 73,
borderRadius: 0
});
annotationView.add(addtoTourView);
addtoTourView.add(addtoTourTitle);
annotationView.add(annotationTitle);
annotations.push(Map.createAnnotation({
latitude: speciesLatitude,
longitude: speciesLongitude,
title: ' ',
//pincolor: Map.ANNOTATION_RED,
image: iconFile,
animate: true,
myid: speciesID,
rightView: annotationView,
leftView: blankView
}));
addtoTourView.addEventListener('click', function(e) {
//alert(speciesName + ' has dded to Tour');
var dialog = Ti.UI.createAlertDialog({
message: 'Added to your Tour',
ok: 'Continue',
title: speciesName //this is the 60th entry, not the correct one
});
dialog.show();
// do the insert into the DB
var db = Ti.Database.open('myDB');
db.execute('INSERT INTO tour (speciesnid) VALUES (?)', speciesID); // same with this ID, needs to the correct ID
db.close();
});
annotationTitle.text = speciesName;
//load up the next record
getSpecies.next();
};
// close the database
getSpecies.close();
// add markers to map
mapview.annotations = annotations;
};// end of loadAnimals fucntion
Can anyone suggest what I'm doing wrong?
Michaels solution sounds right.
Let me post what I was gonna say anyway. I focus on explaining the scope problem, on why your code doesn't do what you expected.
In javascript the scope is bound to the function. When you declare a variable within a loop (for/while/do...) things can get a little confusing. You are not creating new variables, you are just overriding the value of the first (and only) variable with that name.
So, you have 1 variable in function loadAnimals, called speciesName. In the while-loop you just override the value of that variable. After the 60'th iteration, the variable just remembers the last thing you set it to.
When the client clicks on the marker, the loop is finished, the value has been set a long time ago.
Notice: there are probably solutions provided by your map service, but I don't know about that.
1 solution: 'this'.
The 'this' variable tells you what has been affected. Inside a onClick callback, this is the element that was clicked on.
The solution to your problem will probably involve 'this'. But I'm not sure exactly how.
Here an example of what I mean.
<h2>Click on the animal</h2>
<p>dog</p>
<p>cat</p>
<p>hamster</p>
<script>
function loadAnimals() {
var speciesName = '';
var animalElements = document.getElementsByTagName('p');
for (var i=0; i<animalElements.length; i++) {
speciesName = animalElements[i].innerHTML ; // notice, this variable will be overridden, so this variable is useless within the onClick callback.
animalElements[i].addEventListener('click', function(e) {
// variable 'this' is the <p> that was clicked on.
var value_clicked_on = this.innerHTML;
alert(value_clicked_on);
});
}
}
window.onload = loadAnimals;
</script>
When creating your annotations array to add to to the map add your title to the annotation paramters as well as the speciesID which you are setting with the key - myid.
annotations.push(Map.createAnnotation({
latitude: speciesLatitude,
longitude: speciesLongitude,
title: ' ',
//pincolor: Map.ANNOTATION_RED,
image: iconFile,
animate: true,
myid: speciesID, // We'll be querying this
myname: speciesName, // and also this
rightView: annotationView,
leftView: blankView
}));
Then add your event listener once onto the map object instead of each individual annotation object. This manages memory more efficiently and is the correct way to add it. Don't add the event listener on for every annotation, this is bad practise.
// Handle click events on any annotations on this map.
mapview.addEventListener('click', function(evt) {
Ti.API.info("speciesID " + evt.annotation.myid + " clicked, speciesName: " + evt.annotation.myname);
});
On this single event listener you can now create your alert dialog and DB insert by accessing each annotations individual properties by inspecting
evt.annotation
On the Map object you can do the following as well:
The click event includes a value which you can interrogate clicksource
This clicksource will let you know the source - pin, annotation, leftButton, rightButton, leftView, rightView, title, or subtitle which you can use in the event listener.
Also available is the source object that fired the event - source. You can then test if the clicksource is not null and the source is coming from the "ADD TO TOUR" element that you want to place the trigger on. still getting all your annotation properties from evt.annotation
I am doing a meteor app. I have some dynamic infoboxes that will be displayed in google map based on database details . I am trying to give some jquery effect to the infoboxes custom divs when the data inside it changes. The issue is that the jquery effect function is not working, as it seems the div elements creation is not fully complete for it to work. I tried using setTimeout and Meteor.defer, but its still not working. How to overcome this situation ?
Template.myTemplate.rendered = function() {
//some code
if (!rendered) {
//map rendering code
this.rendered = true;
}
for (var i = 0; i < count; i++) {
//some code
var elem = document.createElement("div"); //custom div to be used in infobox
elem.id = i+'_div'; // id is dynamic
elem.innerHTML = '<div><b>' +some_data +'</div>';
var elemInfoBoxOptions = {
content: elem,
disableAutoPan: false,
maxWidth: 0,
pixelOffset: new google.maps.Size(-20, 0),
zIndex: null, boxStyle: {opacity: 1, width: "100px"},
infoBoxClearance: new google.maps.Size(1, 1),
visible: true,
pane: "floatPane",
enableEventPropagation: false,
closeBoxURL: ''
};
var elemInfobox = new InfoBox(elemInfoBoxOptions);
elemInfobox.setPosition(new google.maps.LatLng(latitude, longitude));
elemInfobox.open(map);
$("#"+i+"_div").effect('highlight', {color: 'red'}, 1000); //Tried putting this code inside setTimeout and Meteor.defer. Did not work.
}
};
Thanks.
As I know, jQuery object seems not have a method named 'effect'...
From the looks of it, you want to highlight the just created div element which is referred by the variable elem, so try
$(elem ).effect('highlight', {color: 'red'}, 1000);
Also make sure that the element is added to the dom before the effect is called.
Update: based on updated code
The element elem is not added to the dom tree, you may have to append it to the body like $('body').append(elem)
The id variabel elemID is not changed with in the loop, causing multiple elements with the same id to be created - this is invalid
The selector $("#elemID") is wrong as it looks for an elemetn with id elemID where as elemID is a variable holding the actual id, so it should be $("#" + elemID)
I am currently in the process of putting together a jQuery touch carousel. I seem to have run into a slight problem when setting the height (or width) of an element, however.
Below is the relevant code from the function:
carousel = function( container, options )
{
this.settings = $.extend({
// General settings:
width: 600,
height: 400,
slides: 'div',
snapTo: true,
mouseSupport: true,
trackMovement: true,
slideWidth: 600,
slideHeight: 400,
// CSS classes:
wrapperCls: 'carousel_wrapper',
innerCls: 'carousel_scroll_inner'
}, options);
this.container = container;
this.scroller = null;
this.slides = this.container.children(this.settings.slides);
this.numSlides = this.slides.length;
this.scrollWidth = this.settings.width * this.numSlides;
this.container.addClass(this.settings.wrapperCls);
this.scroller = $('<div />').addClass(this.settings.innerCls);
this.container.wrapInner(this.scroller);
this.scroller.width(1500)
this.scroller.css('width', this.scrollWidth);
this.container.css({ width: this.settings.width, height: this.settings.height });
};
This is in turn called by doing something like:
$(function() {
var carousel1 = new carousel($('#myElement'));
});
#myElement definitely exists, and no error is thrown. this.scroller also contains the correct jQuery object which has been wrapped to the contents of this.container. The problem is that I am unable to set the CSS width or height of this.scroller, using either the width(), height() or css() functions.
What am I missing? I have put together a jsFiddle to demonstrate the problem. If you check the element inspector, you can see that the dimensions are never updated for the div.carousel_scroll_inner element.
The problem is that, here:
this.container.wrapInner(this.scroller);
jQuery will use a copy. So this.scroller is not the same element wrapped around whatever is below this.container. Try:
this.container.addClass(this.settings.wrapperCls);
this.scroller = $('<div />').addClass(this.settings.innerCls);
this.scroller.append(this.container.contents());
this.container.append(this.scroller);
Currently having a problem trying to get YUI Tooltips to display on top of a YUI Panel after it is shown that were previously created. The problem is is that the Panel cannot be registered to the overlay manager because it would require a TON of code to be changed and tested extending a hard deadline. The only way to get this to work is to setup the Tooltips after the Panel is shown. Problem there is the amount of code changes that would have to be done to attach another function call. My problem is that I was hoping that I could use the event handling to use "showEvent" but I cannot seem to get it to work (I apologize for word count):
var panel_obj = new YAHOO.widget.Panel('someID', {
width: "700px",
height: "500px",
close: true,
draggable: false,
modal: true,
constraintoviewport: true,
visible: false,
fixedcenter: true
});
panel_obj.render();
var tooltip_name = 'newTooltip1';
var element_id = 'htmlElementIDToBecomeTooltip';
function createTooltip() {
window[tooltip_name] = new YAHOO.widget.Tooltip(tooltip_name, {
context: element_id,
xyoffset: [15, -15],
zIndex: 999
});
}
function successfulScenario() {
panel_obj.show();
createTooltip();
}
function failedScenario1() {
YAHOO.util.Event.addListener(
'someID',
"showEvent",
createTooltip
);
}
function failedScenario2() {
createTooltip();
panel_obj.show();
}
The only way I have seem to get it working is by running something like successfulScenario(). I'm coming from a jQuery background so I'm still learning YUI. I would love to be able to just extend (subclass) YAHOO.widget.Panel's show() function to call createTooltip but I'm not that much of a guru or I would probably need to change a very large codebase to do it.
try using the "container" property for the tooltip config (so the container would be the panel's element):
function createTooltip() {
window[tooltip_name] = new YAHOO.widget.Tooltip(tooltip_name, {
container: panel_obj.element,
context: element_id,
xyoffset: [15, -15]
});
}
This is the quick solution, using the show event and/or extending the class would be nice but gotta run, if you still need help, I'll check back (also check the example that i made with your code http://jsfiddle.net/3GWaM/2/ ).
function createTooltip() {
var tooltipEl = document.createElement('DIV');
panel_obj.get('element').appendChild(tooltipEl);
window[tooltip_name] = new YAHOO.widget.Tooltip(tooltipEl, {
context: element_id,
xyoffset: [15, -15],
zIndex: 999
});
}
This will ensure the that the tool tip div is created inside the dialog box, instead of in the document body, ensuring it does not appear below the dialog box.
Also, if you want to extend the panel class just do the following
function MyPanel(el, config) {
MyPanel.superclass.constructor.apply(this, arguments);
this.createToolTip();
}
YAHOO.lang.extend(MyPanel, YAHOO.widget.Panel , {
createToolTip: function () {
// create tool tip here
this.on('show', this.showTooltip, this, true);
},
showToolTip: function () {this.toolTip.show();}
});
function getPanelIDFromElementID (element_id) {
var parent_panel = YAHOO.util.Dom.getAncestorByClassName(element_id, 'yui-panel');
var parent_id = null;
if (parent_panel) {
parent_id = parent_panel.id;
}
return parent_id;
}
function createTooltips() {
var tooltip_elements = YAHOO.util.Dom.getElementsByClassName('tooltip');
for (var i = 0; i < tooltip_elements.length; i++) {
var ele_id = tooltip_elements[i].getAttribute('id');
var name = ele_id.charAt(0).toLowerCase() + ele_id.slice(1);
var nameArray = name.split("_");
for (var x=1; x < nameArray.length; x++) {
nameArray[x] = nameArray[x].charAt(0).toUpperCase() + nameArray[x].slice(1);
}
var elementName = nameArray.join('');
window[elementName] = new YAHOO.widget.Tooltip(elementName, {
context: escape(ele_id),
xyoffset: [15, -15],
zIndex: 999,
container: getPanelIDFromElementID(ele_id)
});
}
}