I'm completely baffled. I have some very simple code that takes an object and converts it to JSON.
var vl = JSON.stringify(this.visibleLayers);
This always returns undefined, that is, the variable vl has an undefined value. Yet when I check
JSON.stringify(this.visibleLayers);
in the console, it returns the string I expect. this.visibleLayers is an object, not an array. What could be going on?
EDIT: Adding more code
Below the is the method this is being called in. This is using the Dojo AMD style. Bascially I loop through my map layers and their sublayers to indicate, for each, whether or not the layer is currently visible in the map. So I end up with an object that looks like
{"streets":true,"highways":true,...}
submitExportCustomMap: function() {
domStyle.set("pdfRequestFinished", "display", "none");
domStyle.set("pdfRequestError", "display", "none");
domStyle.set("pdfRequest", "display", "block");
registry.byId("printButton").set("disabled", true);
this.visiblelayers = {};
var _this = this;
array.forEach(map.layerIds, function(layer, i1) {
var ml = map.getLayer(layer);
_this.visiblelayers[ml.id] = ml.visible;
var s = array.forEach(ml.layerInfos, function(sublayer, i2){
if (array.indexOf(ml.visibleLayers, sublayer.id.toString()) !== -1 && ml.visible) {
_this.visiblelayers[sublayer.name] = true;
}
else {
_this.visiblelayers[sublayer.name] = false;
}
});
});
this.prepareCommonParameters();
var vl = JSON.stringify(this.visibleLayers);
var params = {
"xMin": this.extent.xmin,
"yMin": this.extent.ymin,
"xMax": this.extent.xmax,
"yMax": this.extent.ymax,
"Spatial_Reference": this.spatRef,
"Map_Scale": this.mapScale,
"Visiblelayers": vl,
"Layout": this.layout,
"Map_Title": dom.byId("mapTitle").value,
"PointGraphics": graph.getFeatureSet("point"),
"LineGraphics": graph.getFeatureSet("polyline"),
"PolyGraphics": graph.getFeatureSet("polygon")
};
this.cmgp.submitJob(params, lang.hitch(this, this.pdfCompleteCallbackCM), lang.hitch(this, this.pdfStatusCallback), lang.hitch(this, this.pdfErrorCallback));
},
Boy do I feel stupid! It turns out I somehow misstyped visibleLayers. Declaring the variable I called is visiblelayers, with a lower case l. Making the stringify call I use visibleLayers, with a capital L. Making them consistent solved all the problems. D'Oh!
Related
Using Polymer 1 and Web component tester... testing in shady dom on chrome.
In WCT, trying to stub spToast.display() with stub('sp-toast', { display: ()=> {} }); but I get error with Attempted to wrap undefined property display as function.... what I am doing wrong?
The reason why I am trying to stub it is because I get spToast.display is not a function when the test runs the code base.
original code:
showAgeWarning: function() {
var spApp = Polymer.dom(document).querySelector('sp-app');
var spToast = Polymer.dom(spApp.root).querySelector('sp-toast');
var msg = "foo"
spToast.display('information', msg);
},
test code:
<test-fixture id="sp-veteran">
<template>
<h2>edit veteran</h2>
<sp-app>
<sp-toast></sp-toast>
<sp-veteran>
</sp-veteran>
</sp-app>
</template>
</test-fixture>
setup(function() {
replace('sp-app').with('fake-sp-app');
replace('sp-ajax').with('fake-sp-ajax');
stub('sp-value-dropdown', { setInvalidState: (state)=> {} });
myEl = fixture('sp-veteran');
});
test('it should validate the veteran', function() {
var spApp = Polymer.dom(myEl.root).querySelector('sp-app');
var spToast = Polymer.dom(spApp.root).querySelector('sp-toast');
sinon.stub(spToast, 'display');
When you get Attempted to wrap undefined property display as function it means that it can't replace a method that doesn't exist (yet).
If you actually get a value for var spToast = Polymer.dom(spApp.root).querySelector('sp-toast') in your test, and nothing about your test is going to give display a value, you could just set it, a la spToast.display = function() {}; then you should be able to set a spy on it or what have you as needed.
Put it all together and you could have
test('it should validate the veteran', function() {
var spApp = Polymer.dom(myEl.root).querySelector('sp-app');
var spToast = Polymer.dom(spApp.root).querySelector('sp-toast');
spToast.display = function() {};
sinon.spy(spToast, 'display');
// Trigger the side effect that would lead to `display` being called
assert.equal(
spToast.display.calledOnces,
true
);
});
I'm using the 'Compilation.xml' template from the TVMLCatalog
I'd like to add a button click event to a 'listItemLockup'
<listItemLockup>
<ordinal minLength="2" class="ordinalLayout">0</ordinal>
<title>Intro</title>
<subtitle>00</subtitle>
<decorationLabel>(3:42)</decorationLabel>
</listItemLockup>
I've tried adding:
App.onLaunch = function(options) {
var templateURL = 'http://localhost:8000/hello.tvml';
var doc = getDocument(templateURL);
//doc.addEventListener("select", function() { alert("CLICK!") }, false);
var listItemLockupElement = doc.getElementsByTagName("listItemLockup");
listItemLockupElement.addEventListener("select", function() { alert("CLICK!") }, false);
}
addEventListener
void addEventListener (in String type, in Object listener, in optional Object extraInfo)
Is "select" the correct type?
I've been using the following tutorials
http://jamesonquave.com/blog/developing-tvos-apps-for-apple-tv-with-swift/
http://jamesonquave.com/blog/developing-tvos-apps-for-apple-tv-part-2/
Update
I'm getting an error
ITML <Error>: doc.getElementsByTagName is not a function. (In 'doc.getElementsByTagName("listItemLockup")', 'doc.getElementsByTagName' is undefined) - http://localhost:8000/main.js - line:27:58
I tried adding this to the 'onLaunch'
var listItemLockupElements = doc.getElementsByTagName("listItemLockup");
for (var i = 0; i < listItemLockupElements.length; i++) {
//var ele = listItemLockupElements[i].firstChild.nodeValue;
listItemLockupElements[i].addEventListener("select", function() { alert("CLICK!") }, false);
}
I'll see about the error first
Cross Post: https://forums.developer.apple.com/thread/17859
More common example I have seen by Apple is to define a single overall listener like:
doc.addEventListener("select", Presenter.load.bind(Presenter));
In your xml, assign unique ids to elements, or give them ways to identify them.
For example, the beginning would be something like:
load: function(event) {
var self = this,
ele = event.target,
attr_id = ele.getAttribute("id"),
audioURL = ele.getAttribute("audioURL"),
videoURL = ele.getAttribute("videoURL")
And then you can do whatever you want with your item.
if(audioURL && (event.type === "select" || event.type === "play")) {
//
}
My advice would be to study the Presenter.js file more carefully for this pattern.
Edit:
Answering your "Update" related to doc.getElementsByTagName is not a function. "doc" does not actually exist, but the general pattern is to get it with
var doc = getActiveDocument();
I assumed you would know the above.
Does that fix it?
var listItemLockupElement = doc.getElementsByTagName("listItemLockup”);
In this case, the listItemLockupElement is a NodeList, not an element. You can either iterate through the list and add an event listener to each listItemLockup, or you could add the event listener to the containing element.
When addressing items in a NodeList, you use the item(i) method rather than the standard array access notation:
listItemLockupElements.item(i).addEventListener("select", function() { })
See: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/item
Adding event listeners is straightforward if you're using atvjs framework.
ATV.Page.create({
name: 'mypage',
template: your_template_function,
data: your_data,
events: {
select: 'onSelect',
},
// method invoked in the scope of the current object and
// 'this' will be bound to the object at runtime
// so you can easily access methods and properties and even modify them at runtime
onSelect: function(e) {
let element = e.target;
let elementType = element.nodeName.toLowerCase();
if (elementType === 'listitemlockup') {
this.doSomething();
}
},
doSomething: function() {
// some awesome action
}
});
ATV.Navigation.navigate('mypage');
Disclaimer: I am the creator and maintainer of atvjs and as of writing this answer, it is the only JavaScript framework available for Apple TV development using TVML and TVJS. Hence I could provide references only from this framework. The answer should not be mistaken as a biased opinion.
I have been searching how to put more than one function in onchange and I found how something like this for example: onchange = "function1(); function2();".
My problem here is I have followed what does the example like, but only function1 is working, function2 is not working. If I make it otherwise to onchange = "function2(); function1();", only function2 is working, function1 is not working, the same.
Any ideas guys?
Thanks.
The functions, I used Ajax:
function1(test)
{
var kode = test.value;
if (!kode) return;
xmlhttp.open('get', '../template/get_name-opr.php?kode='+kode, true);
xmlhttp.onreadystatechange = function() {
if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200))
{
//alert(kode);
document.getElementById("code").innerHTML = xmlhttp.responseText;
}
return false;
}
xmlhttp.send(null);
}
function2(test)
{
var kode = test.value;
if (!kode) return;
xmlhttp**1**.open('get', '../template/get_name2-opr.php?kode='+kode, true);
xmlhttp**1**.onreadystatechange = function() {
if ((xmlhttp**1**.readyState == 4) && (xmlhttp**1**.status == 200))
{
//alert(kode);
document.getElementById("code2").innerHTML = xmlhttp**1**.responseText;
}
return false;
}
xmlhttp**1**.send(null);
}
To solve my problem, I created two xmlhttp different. (xmlhttp and xmlhttp1).
Go through the link I gave, it seems to be problem with the way you are managing the xmlhttprequest objects, manage their instances properly, in your case because you are using the same xmlhttprequest for two simultaneous AJAX requests, only one of them is getting served. Either wait for one of them to get served or create two instances of the xmlhttprequest.
The statement xmlhttp.readystate = function() {...} obviously replaces the readystate property of that xmlhttprequest object, so on your second function, that is being replaced( because you are using the xmlhttprequest for both of them ). This is why you are seeing the funny behaviour.
Call function2() at the end of function1().
onchange = "function1()"
function1(){
...
function1 body;
...
function2()
}
Wrap the two function calls in one and call that function!
function myFirstFunction() {
//body
}
function mySecondFunction() {
//body
}
//Call this guy.
function myWrappedFunction() {
myFirstFunction();
mySecondFunction();
}
I'm using the mootools wall plugin, Its working well in my application, however if I add multiple (image) walls it only works for one wall ::: My understanding of scripting is not good enough to add a each function or similar :::
I need to "bind" the code below to say 2 divs like this :::
My First wall:
<div id="viewport">
<div id="wall">
Second wall:
<div id="viewport">
<div id="wall_02">
Any assistance would be appreciated.
var wallIMAGES = new Wall( "wall", {
"width": scArray[1],
"height": scArray[1],
callOnUpdate: function(items){
items.each(function(e, i){
var el = wall[counterFluid];
if (el) {
var a = new Element("img[width="+scArray[1]+"][height="+scArray[1]+"][src={thumb}]".substitute(el));
a.inject(e.node).set("opacity", 0).fade("in");
e.node.store("tubeObject", el);
}
counterFluid++;
// Reset counter
if( counterFluid >= scArray[10].length) counterFluid = 0;
})
}
});
wallIMAGES.initWall();
Maybe something like this:
var my_wall_ids = ['wall', 'wall_02'];
var myWalls = [];
var baseWallOptions = {
"width": scArray[1],
"height": scArray[1],
callOnUpdate: function(items){
items.each(function(e, i){
var el = wall[counterFluid];
if (el) {
var a = new Element("img[width="+scArray[1]+"][height="+scArray[1]+"][src={thumb}]".substitute(el));
a.inject(e.node).set("opacity", 0).fade("in");
e.node.store("tubeObject", el);
}
counterFluid++;
// Reset counter
if( counterFluid >= scArray[10].length) {counterFluid = 0;}
}); // end items.each
}
}
for (var i=0;i<my_wall_ids.length;i++){
var id = my_wall_ids[i];
var wallOptions = baseWallOptions;
// if your customization was something like changing
// the height , but only on the 'wall' element
if (id === 'wall') {
wallOptions.height = 400;
}
myWalls[i] = new Wall(id, wallOptions);
myWalls[i].initWall();
}
If you read Wall's documentation, you'll notice that, just like most other classes, the first argument it takes is an element id.
So, if your initialization code states
new Wall("wall", { …
…then it will be applied to the element that has the id "wall".
You could simply duplicate your code and use one with "wall", the other one with "wall_02". However, that would be bad practice. Indeed, if you later wanted to change some options, you'd have to do it in two distinct blocks, and they would probably get out of sync.
If your only difference lies in the target id, and the options are to be shared, simply store the options object (second parameter to the Wall class) in a variable and use it twice! That is:
var wallOptions = { width: … };
var wallImages = new Wall("wall", wallOptions),
wallImages2 = new Wall("wall_02", wallOptions);
wallImages.initWall();
wallImages2.initWall();
It could be even better to embed initalization in a function, but this solution is probably the easiest if you simply want to have two Wall instances without learning much more about JS.
how to access outer function's argument 'parent' ??? please see comments in code
!!last edit : This question is misleading, my problem is caused by wrong input argument
renderData : function(parent, children){
children.each(function(e, index){
var li = new Element('li');
var hasChildren = false;
if(e.children && e.children.length >0){
var img = new Element('img');
img.src = 'a1.png';
img.inject(li);
hasChildren = true;
}
if(e.icon){
var img = new Element('img');
img.src = e.icon;
img.inject(li);
}else{
var img = new Element('img');
img.src = 'b1.png';
img.inject(li);
}
li.set('html',e.text);
console.log(this);
// how to access outer function's argument 'parent' ???
li.inject(parent);
if(hasChildren){
var ul = new Element('ul');
this.renderData(ul, e.childRen);
ul.inject(e);
}
}.bind(this));
within an each loop:
array.each(function(el) {
this.method(); // this == (instance / scope)
}, this); // where **this** is your parent scope.
another acceptable way is:
var self = this;
...
array.each(function(el) {
self.method(); // fine.
}); // where this is your parent scope.
http://mootools.net/docs/core/Types/Array#Array:Array-each
although, using .bind(this) should work too... http://www.jsfiddle.net/dimitar/fFy4J/ - so what is the problem?
if i understood correctly, your problem is that you cant do li.inject(parent)
there's no reason why you can't access 'parent' since it's been passed as a parameter to the function renderData()
I've tried this simple test
var test;
window.addEvent('domready', function(){
test = new TestClass();
});
var TestClass = new Class({
Implements: [Options, Events],
initialize: function(){
this.renderData($('parent'),$$('span'))
},
renderData : function(parent, children){
children.each(function(e, index){
console.log(parent);
}.bind(this));
}
});
and it works fine... but i'm no really sure what's the problem on your code