In an attempt to create polymer elements that use requirejs modules I ran into a blocking issue. I understand that polymer is not designed to work with requirejs, but for the time being It is my only option.
Searching for answers I found two solutions:
Don't use requirejs and make your modules compatible with HTML imports.
Put Polymer() call inside the requirejs callback as described here
Since I have to use require, at least for the time being, I went with the solution no.2. However, it turns out the solution causes asynchronous delays of element registration and incorrect data binding prior to Polymer upgrading the element.
Digging deeper into this issue, I started hacking undocumented Polymer internals with an intention to stop Polymer entirely until requirejs does its thing. Here is what I came up with:
Polymer.require = function(tag, deps, func) {
var stopper = {}
Polymer.queue.wait(stopper);
require(deps, function() {
delete stopper.__queue;
Polymer.queue.check();
Polymer(tag, func.apply(this, arguments));
});
};
I know this is terribly wrong. Is there a better solution?
I found that if I embed the call to require within the Polymer script I avoid this issue.
<link rel="import" href="../polymer/polymer.html"/>
<script src="../requirejs/require.js"></script>
<script src="../something/something.js"></script>
<polymer-element name="some-component">
<template>...</template>
<script>
(function() {
Polymer('some-component', {
someMethod: function () {
require(['something'], function (Something) {
var something = new Something();
...
}
}
)();
</script>
</polymer-element>
So there's this solution from Scott Miles but I find it a bit simplistic and inflexible as it relies on:
<script> tags to be executed in order, therefore ruling out:
async script tags
xhr based script loading
polymer getting loaded from a <script> tag, therefore:
layout.html and associated css won't be loaded
any future call to polymer.html won't be deduped
If you want more control over your bootstrapping logic you will need to enforce some amount of synchronisation between your components (which is what both requirejs and polymer are competing to do) before those are fully loaded.
The previous example is a more declarative (read polymer) way of doing things but falls short of fine grained tuning. I've started working on a repository to show how you can fully customise your load ordering, by using a more imperative approach where requirejs is given priority to orchestrate the rest of the bootstrapping.
At the time of writing, this extra control comes at the price of worse performance as the various scripts can't be loaded in parallel but I'm still working on optimising this.
Related
I have a ASP.NET Core application which renders tables on the serverside, some are quite complex.
I used to use sorttable: Make all your tables sortable for make the tables sortable; now as I have included vue.js (2.0, without npm / webpack), the jquery plugin obviously does no longer work properly.
Now, before i transition fully over to 100% clientside table rendering - which I want to avoid for now, if its possible, cause its complex - is there something similar to add sorting to a rendered html with vue or is that concept that old and no longer viable in vue.js and other modern frameworks?
So, questions are:
How to make sorttable work in vue.js are (without npm / webpack)
Or how to add something like that to a already server rendered html with vue?
Looking forward and regards, Peter
Okay, got it. That was a journey :-)
Sorttable script: https://www.kryogenix.org/code/browser/sorttable/
The script:
Vue.component('date-table', {
template: '<div><slot></slot></div>',
props: ['innerHtml'],
mounted: function () {
var self = this;
sorttable.makeSortable(this.$el.firstChild);
},
beforeDestroy: function () {
}
});
The markup:
<date-table v-once>
HERE IS MY ORDINARY HTML WHICH SHOULD BE SORTED BY
"sortable.makeSortable(...."
</data-table>
Latest Update (also updated post title)
So I tracked down the issue to the old version of Mootools (which I cannot upgrade or remove due to project restrictions).
Mootools does the following, which is the code that causes the issue:
/*
Class: Abstract
Abstract class, to be used as singleton. Will add .extend to any object
Arguments:
an object
Returns:
the object with an .extend property, equivalent to <$extend>.
*/
var Abstract = function(obj){
obj = obj || {};
obj.extend = $extend;
return obj;
};
//window, document
var Window = new Abstract(window);
var Document = new Abstract(document);
The new definitions of Window and Document is what's breaking Polymer imports. Any suggestions on updating the code above to gracefully extend the Document/Window objects without breaking existing functionality?
OLD description below before I discovered the issue lies with mootools
I've already included the webcomponents.js script.
Then, when I have the for polymer.html, the errors below start appearing, and my polymer components doesn't work.
The components works in isolation using the polymer-cli. Anyone know what may be causing this issue?
EDIT: So this is what I have in my <head>
<script src="/media/bower_components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="/media/bower_components/polymer/polymer.html">
(...sorry I cannot show more, private company code and what-not)
That's literally all I need in my page to raise the error mentioned above.
I'm starting to think there is some other javascript library (there's a lot) that might be interfering with Polymer, since I cannot replicate the issue on a brand new site.
I should also note, there are no 404's. The polymer.html file does get loaded as expected in the browser, I verified this in my network panel in developer console.
I'm new to Polymer 1.0.
I get the whole "everything is an element" philosophy but, to what extent?
How to structure all theses elements together?
TL;DR: Is there an equivalent to the main() function with Polymer and WebComponents in general ? If so , where should it be and what should it do ?
I usually look at examples, demos and projects to see how it should work, but because Polymer is so new (especially v1.0), I have a hard time finding non-trivial examples.
Long version
I get how to use Polymer to create elements.
But I'm hitting a roadbloack when I want to interface them. What structure shoud I use to make components talk between them.
Coming from an Angular background I have a relatively precise view of what should go where.
For example: the data is contained within scopes which are accessible from controllers, directives and html elements and you can use services to pull data from different part of the app.
In Polymer I don't get where are the boundaries of the data.
Not in the component itself but outside of it, where it lives and if another component can access it.
A simple drawing could help me a lot. There is no such thing explained in the polymer docs, probably because it's broader than Polymer.
To give you insights on my problem this is what I came across:
I set up a SPA based on Polymer Starter Kit
I wanted to wire it to firebase with the firebase-element
I created my own element which itself use <firebase-auth>:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/firebase-element/firebase-auth.html">
<dom-module id="my-login">
<template>
<firebase-auth id="firebaseLogin"
user="{{user}}"
location="https://my-project.firebaseio.com"
provider="facebook"
on-error="_errorHandler"
on-login="_loginHandler"></firebase-auth>
<button on-tap="login">Login with facebook</button>
<button on-tap="logout">Logout</button>
</template>
</dom-module>
<script>
Polymer({
is: 'my-login',
properties: {
successRedirect: String
},
_errorHandler: function(e){
console.log(e.detail);
},
_loginHandler: function(e){
if(this.successRedirect){
// How can I tell pagejs to redirect me ?
app.route = this.successRedirect;
}
}
});
</script>
Basically How do I tell pagejs (my routing library) to redirect the app to a page after a successful login ? My pagejs config lives in it's own routing.html file and I don't understand how to piece together all of this.
I hope someone will be abe to understand this broad question and hopefully help me.
Thanks
Short answer: Event Listeners. Place an event listener on your router. Have the login handler fire the event on the router. The router will pick up that event and then redirect.
...
_loginHandler: function(e){
if(this.successRedirect){
// How can I tell pagejs to redirect me ?
var router = document.querySelector('router');
router.dispatchEvent(new Event('redirect', {redirectURL: this.successRedirect});
app.route = this.successRedirect;
}
}
...
Then in your router:
connectedCallback() {
this.addEventListener('redirect', function(event) {
var url = event.redirectURL;
// Redirect using the router's API.
});
}
I have an Angular controller which makes a call to $http.get.
app.controller('dataController', function dataController($scope,$http) {
$http.get(URL)
.success(function(response) {$scope.jobs = response;});
});
This call works fine with small files but I have a json file that is 1.2MB in size (57,000 lines) that seems to be breaking my application. Is this a known issue? Are there any workarounds?
If you are two way binding to each element in each row then you will probably get a performance hit on the digest cycle.
Maybe you should page the data into the DOM.
ngGrid is good for this!
Or use angular 1.3 one way binding.
Is it possible to access google closure library functions from google app scripts via HtmlService? The html files in the google scripts seems to be filtering out anything related to closure library.
project: I am exploring DOM manipulation utilities from Google Closure library from within the google app scripts using HtmlService. I intend to run this as a stand alone web app.
The closure functions work when directly loaded into the browser from its local client environment - but they dont work when injected from GAS app via the HtmlService utility.
Here is the code I am using in the GAS.
html file
<html>
<head>
<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
<script>
goog.require('goog.dom');
function c_sayHi() {
var newHeader = goog.dom.createDom('h1', {'style': 'background-color:#EEE'},'Hello world!');
goog.dom.appendChild(document.body, newHeader);
}
</script>
</head>
<script>
function c_updateButton(date, button) {
button.value = "clicked at " + date;
}
</script>
<body onload="c_sayHi()">
<input type='button' value='Never Clicked'
onclick='google.script.run.withSuccessHandler(c_updateButton).withUserObject(this).s_getCurrentDate()'>
<input type='button' value='Never Clicked'
onclick='google.script.run.withSuccessHandler(c_updateButton).withUserObject(this).s_getCurrentDate()'>
</body>
</html>
Google Script file
function s_getCurrentDate() {
return new Date().toString();
}
function doGet(e) {
return HtmlService.createTemplateFromFile('hello').evaluate();
}
I have prefixed c_ to client side functions and s_ for server side fns. When running this as a web app,
Function c_sayHi has no effect - I am not sure if it is even invoked.
Functions s_getCurrentDate and c_updateButton work fine as described in google's documentation https://developers.google.com/apps-script/html_service.
Is there a way to get closure library working from the web apps as attempted above?
Couple of things here -
All .gs files is JavaScript that runs on the server side. So the DOM is not really relevant there.
You can run client side JavaScript by returning code in HtmlService. This is what I believe you want to do. However, jQuery is the best supported library on this approach. Closure might end up working but the team does not specifically test against that library.
The problem is that Closure's dependency structure is executing before the window load event, otherwise it will not work. So any require and provide statements are taken care of way before window load. When you inject them through the HTML Service, you are forcing their execution at a different stage then required, which causes everything to fail.
If you would be using a COMPILED Closure Library source, you will not have any problems with running Closure. Learn how to use the Compiler and Builder to make Closure Work properly. Also, you can use lazy loading to simulate your HTML Service.
With that, you can make javascript load dynamically onclick, onload or whatever the hell you want. This is called lazy-loading and it is used as a standard practice for all large web applications. Monitor the Network tab of Firebug when browsing through Gmail or Facebook.
Arun Nagarajan is right, jQuery is the easier solution but if you are doing something proper that requires breadth, scale and speed, jQuery is a toy for kids.