Polymer 2 access file uploaded in another page - polymer

I am using a simple polymer application with few pages in iron-pages. I am uploading a file in one page and then I want to access this uploaded file in another page.
I tried several things but nothing seems to work, here is the sample code
Page in which file is uploaded
<dom-module id="file-upload-page">
<template>
<form method="post" enctype="multipart/form-data" action="/someation" disable-native-validation-ui no-validate>
<my-input file={{file}} id="sampleFileInput" btn-style="primary" max-files="1" accept=".xls, .xlsx" on-drop="fileUploadChangeListener"
label="[[localize('open_invoices_file')]]" help-text="[[localize('open_invoices_file_help')]]" no-auto required>
</my-input>
</form>
</template>
<script>
class FileUploadPge extends Polymer.mixinBehaviors([], Polymer.Element) {
static get is() {
return 'file-upload-page';
}
static get properties() {
return {
}
}
}
customElements.define(FileUploadPge.is, FileUploadPge);
</script>
</dom-module>
Page in which file is accessed
<dom-module id="consumer-page">
<template>
//some code
</template>
<script>
class ConsumerPage extends Polymer.mixinBehaviors([], Polymer.Element) {
static get is() {
return 'consumer-page';
}
constructor() {
super();
}
static get properties() {
return {
//some properties
}
}
ready() {
super.ready();
var temp2 = this.$.sampleFileInput; // returns null
var temp3 = this.shadowRoot.querySelector("#sampleFileInput"); // returns null
var temp4 = this.root.querySelector('#sampleFileInput'); // returns null
var temp5 = this.$$('#sampleFileInput'); // returns null
this._refreshSelections();
};
_proceed() {
var test1 = Polymer.dom(this).querySelector("#sampleFileInput"); // returns null
var test2 = this.$.sampleFileInput; //returns null
var test3 = document.getElementById("sampleFileInput"); //returns null
var test4 = this.$$("sampleFileInput"); //returns null
var test5 = this.shadowRoot; //returns some object
var test6 = this.$$.sampleFileInput; //returns null
var test7 = document.querySelector('sampleFileInput'); //returns null
var test8 = document.querySelector('file-upload-page::shadow .FileUploadPge'); //returns null
var temp4 = this.root.querySelector('#sampleFileInput');//returns null
var temp5 = this.$$('#sampleFileInput');//returns null
var temp6 = this.shadowRoot.querySelector('#sampleFileInput'); // returns null
};
}
customElements.define(ConusmerPage.is, ConusmerPage);
</script>
</dom-module>
The same code works in polymer1.0 with this
document.getElementById("sampleFileInput")
Can somebody help what wrong am I doing in accessing this file in other page, and how can I handle this scenario in Polymer 2.0?

As you said in consumer-page you're trying to access the #sampleFileInput element which is a child of another component.
All of these attempts:
var temp2 = this.$.sampleFileInput;
var temp3 = this.shadowRoot.querySelector("#sampleFileInput");
var temp4 = this.root.querySelector('#sampleFileInput');
var temp5 = this.$$('#sampleFileInput');
var test1 = Polymer.dom(this).querySelector("#sampleFileInput");
fail because you're trying to access an element which is not present inside consumer-page's template, while these:
var test7 = document.querySelector('sampleFileInput');
var test8 = document.querySelector('file-upload-page::shadow .FileUploadPage');
fail respectively because document.querySelector() cannot select inside shadow dom and ::shadow and /deep/ selectors were deprecated (see here).
Technically you should be able to select #sampleFileInput inside consumer-page this way:
this.parentElement // Goes back to iron-pages
.querySelector('file-upload-page') // Selects file-upload-page
.shadowRoot // Enters its shadow root
.querySelector('#sampleFileInput'); // Selects the file uploader
however accessing elements inside others' shadow root is considered a not so good practice not to mention that if you're using lazy loading for iron-pages pages this will fail if file-upload-page wasn't loaded.
There are instead many other ways to expose information outside of custom elements such as events or properties.
You could, if it can fit with your implementation, use the component holding iron-pages as coordinator of your procedure and use attributes bindings to notify it with the data it needs from the different pages as the user goes on filling.
IE in file-upload-page bind the uploaded file url to a property, and observe it in the parent:
<iron-pages>
<file-upload-page url="{{url}}"></file-upload-page>
<consumer-page></consumer-page>
</iron-pages>
<script>
class Parent extends PolymerElement {
// ...
static get properties() {
return {
url: {
type: String,
reflectToAttribute: true,
observer: '_urlChanged',
},
};
}
_urlChanged() {
console.log(this.url);
}
// ...
}
</script>

Related

Function inside a Function not calling in React Native

I am new to react-native and calling a function inside a fucntion.
I have done as below so far :
Step 1 : Created a function _snapshotToArray to convert the firebase snapshot to Arrray.
_snapshotToArray(snapshot) {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
var item = childSnapshot.val();
item.key = childSnapshot.key;
returnArr.push(item);
});
return returnArr;
}
Step 2 : Created another function as below and calling _snapshotToArray inside it.
_readUserDataFromFirebaseConsole() {//once and on
firebase.database().ref('Users/').on('value', function (snapshot) {
console.log(this._snapshotToArray(snapshot));
Toast.show(this._snapshotToArray(snapshot),Toast.LONG);
});
}
Talking about this call :
console.log(this._snapshotToArray(snapshot));
When I press CTRL+CLick, it not letting me to navigate to body of the fuction _snapshotToArray.
In Device am getting below error :
_snapshotToArray is not defined
What might be the issue ?
I'm not at my PC right now, so I cannot test it, but from looking at your code, you need to use a different function notation to allow the varibale access of/from parent methods and parent class.
_snapshotToArray = snapshot => {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
var item = childSnapshot.val();
item.key = childSnapshot.key;
returnArr.push(item);
});
return returnArr;
}
and
_readUserDataFromFirebaseConsole = () => {
firebase.database().ref('Users/').on('value', snapshot => {
console.log(this._snapshotToArray(snapshot));
Toast.show(this._snapshotToArray(snapshot),Toast.LONG);
});
}

Assigning value to variables in polymer

Polymer doesn't bind data if we assign value to polymer multiple times.
For example:
Polymer({
is: "g-feed",
properties: {
event: String
},
ready: ()=> {
var self = this;
self.news = [];
var nws = [];
nws.push({nm:'One'});
nws.push({nm:'Two'});
self.news = nws;
nws.push({nm:'One1'});
nws.push({nm:'Twoa'});
self.news = nws;
console.log(self.news);
}
});
Here the news array would only hold the values "one" and "two" rendered on the webpage.
Can you please tell me why this happens and how to overcome this. Also, how to work with consistantly changing data in polymer.
Thanks.

Can not stub private element in WCT

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
);
});

TVML listItemLockup click event

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.

How to handle tvOS MenuBarTemplate selection?

I have a basic MenuBarTemplate set up and displaying.
How do I react to a user's Menu selection and load an appropriate content template?
In the menuItem tag include a template attribute pointing to the template to load and a presentation attribute set to menuBarItemPresenter.
<menuItem template="${this.BASEURL}templates/Explore.xml.js"
presentation="menuBarItemPresenter">
<title>Explore</title>
</menuItem>
You can then use the menu bar's MenuBarDocument feature to associate a document to each menu bar item.
menuBarItemPresenter: function(xml, ele) {
var feature = ele.parentNode.getFeature("MenuBarDocument");
if (feature) {
var currentDoc = feature.getDocument(ele);
if (!currentDoc) {
feature.setDocument(xml, ele);
}
}
This assumes you're using a Presenter.js file like the one in Apple's "TVML Catalog" sample. The load function specified there is what calls the function specified in the menuItem's presentation attribute.
I suppose that TVML and TVJS is similar with HTML and Javascript. When we want to add some interaction into the user interface, we should addEventListener to DOM.
In Apple's "TVML Catalog", Presenter.js is a nice example, but it is abstract, and it could be used in different Present actions.
When I develop my app, I had wrote this demo for handling menuBar selection.
Module : loadTemplate.js
var loadTemplate = function ( baseURL , templateData ){
if( !baseURL ){
throw("baseURL is required");
}
this.BASEURL = baseURL;
this.tpData = templateData;
}
loadTemplate.prototype.loadResource = function ( resource , callback ){
var self = this;
evaluateScripts([resource], function(success) {
if (success) {
var resource = Template.call(self);
callback.call(self, resource);
} else {
var title = "Resource Loader Error",
description = `There was an error attempting to load the resource '${resource}'. \n\n Please try again later.`,
alert = createAlert(title, description);
Presenter.removeLoadingIndicator();
navigationDocument.presentModal(alert);
}
});
}
module.exports = loadTemplate;
Module nav.js ( use menuBarTemplate ) :
import loadTemplate from '../helpers/loadTemplates.js'
let nav = function ( baseURL ){
var loader = new loadTemplate(
baseURL ,
{
"explore" : "EXPLORE",
"subscribe" : "SUBSCRIBE",
"profile" : "PROFILE",
"settings" : "SETTINGS"
}//need to use i18n here
);
loader.loadResource(`${baseURL}templates/main.xml.js`, function (resource){
var parser = new DOMParser();
var navDoc = parser.parseFromString(resource, "application/xml");
navDoc.addEventListener("select" , function ( event ){
console.log( event );
var ele = event.target,
templateURL = ele.getAttribute("template");
if (templateURL) {
loader.loadResource(templateURL,
function(resource) {
if (resource) {
let newParser = new DOMParser();
var doc = newParser.parseFromString( resource , "application/xml" );
var menuBarItemPresenter = function ( xml , ele ){
var feature = ele.parentNode.getFeature("MenuBarDocument");
if( feature ){
var currentDoc = feature.getDocument( ele );
if( !currentDoc ){
feature.setDocument( xml , ele );
}
}
};
menuBarItemPresenter( doc , ele );
}
}
);
}
});
navigationDocument.pushDocument(navDoc);
});//load from teamplate.
}
module.exports = nav;
My code is not the best practice, but as you can see, you just need to addEventListener like you are writing a web application. Then you can handle menuBarTemplate selection easily, even after XHR loading.
Avoid too many callbacks, you should rebuild your code again and again. :-)