Polymer 1.0 data binding on custom element for pagination - data-binding

I am learning Polymer to make a small single page app.
I would like to manage pagination as it is done in the Polymer starter kit, but without using the template dom-bind (because I need one later in the page, and we cannot have one nested in another).
So, I tried to make my own custom element in order to bind its attribute "route" to the iron-pages element. But, as you can imagine, it did not work.
So I tried to make data binding work in a small example. As shown in the "Quick Tour of Polymer", I have made a custom element in "pagination-element.html" :
<link rel="import" href="../bower_components/polymer/polymer.html">
<script>
Polymer({
is: "pagination-element",
properties:{
route : {type:String, value:"/", notify : true}
}
});
</script>
and using it in my page (I have checked that pagination-element.html is imported) :
<pagination-element id="app" route="/">
<paper-input label="{{ route }}"></paper-input>
</pagination-element>
Then, I tried to get the "route" value with an other Polymer custom element, but it only displays me "{{route}}" on my page.
I think I have not understood how data binding works...
Can anyone help me ?
Thanks a lot !
Have a good day

On your page you will need to wrap your pagination-element in an auto binding template using (unless you are using this inside another element):
<template is="dom-bind">
In your paper-input you are setting the label to be the value of route but you have not given route a value. I'm guessing you want the value of it to be that of the route property on the pagination-element:
So in your index.html or other page:
<body unresolved>
<template is="dom-bind">
<pagination-element id="app" route="{{route}}">
<paper-input label="{{route}}"></paper-input>
</pagination-element>
</template>
</body>

Related

Nuxt3 navigateTo gives Uncaught (in promise) TypeError

I am trying to programmatically route to a detail page from within a list in Nuuxt3 app:
#/pages/items/index.vue
<script setup lang="ts">
const gotoDetail = async (itemId) => {
await navigateTo(`/items/${itemId}`)
}
</script>
<template>
<div>
<NuxtLayout name="main-standard">
<template #main-content>
<div v-for='item in items' :key=item>
<div #click='gotoDetail(item.id)'
</div>
</template>
<template #main-content>
<!-- aside content -->
</template>
<NuxtLayout>
</div>
</template>
And I am getting this error message:
ERROR: Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode')
I have searched for an answer and most solutions mention to wrap the <NuxtLayout> with a div. But that did'nt solve my issue.
I am using a default Layout. So the<NuxtLayout name="main-standard"> is inside this default layout. Both pages: index.vue and [itemId].vue are in the pages/items/ folder.
I am doing something wrong but just can't find it. Does anyone see whats going on?
A few things here are going to break your code.
One, the middle div with the click handler is missing a closing >, contents, and a closing </div>. (Of course you may have omitted that for brevity)
items isn't defined, so there's nothing to iterate over.
You're using the same v-slot name #main-content for multiple templates, but each slot name should be unique. The # attributes (shorthand for v-slot) should match the slot names you write in your layout, and those must also be unique within the component.
The main problem looks to be related to the way you're using layouts. To mess with layout on a page using the component, you have to add this into the setup script:
definePageMeta({
layout: false,
});
A different way of applying your custom layout to this page is to replace the false boolean with the name of the layout, and omit the tag from this page altogether. For that to work, app.vue should have a <NuxtLayout> tag wrapping the <NuxtPage>
Not a breaking change, but it may also simplify things to write
<NuxtLink :to="`/items/${itemId}`">{{ whatever you wanted inside that div }} </NuxtLink>
If you need to run code before navigating to that page, you can add it into the top-level middleware folder, and call that named middleware on the page before which you want it to run.

Insert custom HTML in page DOM with Google Tag Manager

I've implemented GTM on my website. I'm wondering if is possible to add custom HTML/JS in a specific position of the DOM.
This is what I've inserted in my page:
<div class="myClass">
<p>foo</p>
<script>
dataLayer.push({'event':'myEvent'})
</script>
</div>
and on GTM I've set up a tag with this html:
<div class="test">this is a test</div>
<iframe src="www.foo.com" />
which is triggered on myEvent.
Unfortunatly this is not working correctly, my tag is inserted at the bottom of my web page and not inside the myClass div.
Am I doing something wrong or this is just not allowed by GTM?
Thanks.
"Not allowed" is perhaps a bit strong (as you can see it works to some extent), but tags that change visual aspects of the page are generally not recommended.
If you want to insert HTML at a specific location it would be better to create the element dynamically via javascript and append it to an existing element, so your HTML tag would look something like (untested):
<script>
var myDiv = document.createElement('div');
myDiv.setAttribute('class','test');
var container = document.querySelector('.myClass');
container.append(myDiv);
</script>
You would need to make sure that the element you append to is unique (if possible add an id rather than a class name). Tags are executed asynchronously, so it's a bit hard to say at which point in the loading process the HTML is appended (this will cause a reflow in the DOM which is an expensive operation for the client, so you do not want to do this too often).

Iron router sublayouts - getting data context on yield

Consider the following templates:
layout
pageLayoutStandard
aboutUs
'layout' is my top-level template, which I specify using:
Router.configure({
layoutTemplate: 'layout',
});
Inside layout.html I have the following:
<main id="site-main" role="main">
{{>Template.dynamic template=page.pageLayoutTemplate }}
</main>
I pass some data in from the route: a page object which has a property 'pageLayoutTemplate', having the value 'pageLayoutStandard'.
Inside 'pageLayoutStandard' template, I have:
{{> yield }}
If I visit the '/about-us' route, I render the 'aboutUs' template into 'pageLayoutStandard' - no worries.
And now to my problem...
In my 'aboutUs' template, I expect the 'data' property of the instance to contain the data I passed down from iron-router. However, I find that my the data property contains a 'Template' object; specifically, it contains 'pageLayoutStandard'.
So it looks like 'yield' doesn't like living in a sub-layout - it wants to live at the top level layout for it to get the data from the route. This I validated by moving my yield to the top level layout - the 'aboutUs' template then gets the right data.
Is there any way I can get 'yield' to get the correct data context when it exists in a sublayout?
One solution is to access the data using
Router.current().data()
I my self am fairly new to Iron-Router, but I believe it may be a similar issue that I cam across in another way. There are also several ambiguities in your question, such as where and how are you specifically defining the data context.
Basically I discovered that {{> yield}} creates it's own <body> tags. This also means that things like Template.body.events(); don't propagate into this new Iron-router <body>. This is a known "bug" with Iron-Router.
There is a workaround that has been developed to solve that particular issue, but I'm not sure it's relevant to your case, or at least may not solve the problem since you are not looking to propagate the main body template.
In the end it may be that your routing logic is somewhat inverted, as you mentioned, with the intended usage of Iron-Router.
I believe a better way to perform what you want would be to have:
<main id="site-main" role="main">
{{> yield}}
</main>
With something like this in your router definition
Router.map(function (){
this.route("/about-us", {
template: "pageLayoutStandard"
}
});
You should then be able to set your data context and rendering as per usual.

Template.body vs Template.myTemplate

I am currently going through the Meteor tutorial (https://www.meteor.com/try), and have come across something about Templates that puzzles me.
In the tutorial, a simple "Todo List" application gets created. In this app, the following HTML is placed into the simple-todos.html file:
<!-- simple-todos.html -->
<head>
<title>Todo List</title>
</head>
<body>
<div class="container">
<header>
<h1>Todo List</h1>
</header>
<ul>
{{#each tasks}}
{{> task}}
{{/each}}
</ul>
</div>
</body>
<template name="task">
<li>{{text}}</li>
</template>
Then, the following JavaScript is placed into the simple-todos.js file:
// simple-todos.js
Tasks = new Mongo.Collection("tasks");
if (Meteor.isClient) {
// This code only runs on the client
Template.body.helpers({
tasks: function () {
return Tasks.find({});
}
});
}
At this point, the example works exactly as intended. However, as I poke around in the documentation, as well as look at other examples on the web, I have noticed slightly different syntax: using Template.myTemplate instead of Template.body.
So, out of curiosity, I altered my JavaScript file to read:
Template.task.helpers({ ...
instead of:
Template.body.helpers({ ...
However, when I run the application now, the client does not display the data from the collection. I don't get any errors about undefined types, like I do if I misspell the template name in the JavaScript, so it seems that it is resolving the template correctly. But why isn't it getting used or rendered?
And to go a little further: when is it appropriate to use Template.myTemplate and when is it appropriate to use Template.body?
The helpers code only works for the template it's attached too.
So, code that works for Template.task will only apply to templates named "task".
Template.body is like the one-off that exists because it would be weird if it didn't. It's a way for you to specifically target the <body>, even though technically, there's no template named "body".
So, what is going on:
Parent template = body
Child template = task
Your logic says:
In the parent template, for each task that we find, render an instance of the child template "task".
If you change your helper from body to task, you won't get any output at all, unless you mimic the pattern that's already happening:
<template name="task">
{{#each tasks}}
do something
{{/each}}
</template>
That's because <body> is the parent template, and you should treat it as such:
<template="body>stuff that normally goes in an HTML body here</template>
When you remove the helpers for the body, then no data gets displayed at all because helpers pass data into the template. And with no helper for the template i.e. the body, you get no data.

how to get google translate for section with dropdown list of languages working?

I'm trying to use google translate for translations of user comments. I'm using the official wizard (http://translate.google.com/translate_tools) to generate the java script and html code:
<script>
function googleSectionalElementInit() {
new google.translate.SectionalElement({
sectionalNodeClassName: 'goog-trans-section',
controlNodeClassName: 'goog-trans-control',
background: '#f4fa58'
}, 'google_sectional_element');
}
</script>
<script src="//translate.google.com/translate_a/element.js?cb=googleSectionalElementInit&ug=section&hl=auto"></script>
<div class="goog-trans-section">
<div class="goog-trans-control">
</div>
some text in some language
</div>
I don't want the entire page to be translated, but only the comments. Unfortunately, the code generated for section translation doesn't come with a dropdown box for language selection. Does somebody know how to implement this? I tried to add includedLanguages: 'en,fr,de,ru', to the java script code, but it didn't help.
The super simple thing is just use the steps below.
1. add the following code where you want to show the translate dropdown.
<div id="google_translate_element"></div>
<script>
function googleTranslateElementInit() {
new google.translate.TranslateElement({
pageLanguage: 'en'
}, 'google_translate_element');
}
</script>
<script src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
add class="notranslate" to body tag
add class="translate" to the section which you want to be translated by google translate.
It seems the sectional translation widget behaves differently to how I was expecting (and maybe differently to how you were expecting too). The "entire webpage" widget gives you a dropdown and lets the user choose which language they want to display the page in.
The "section of the webpage" widget appears to be intended to deal with sites which have individual sections in different languages where you want the user to be able to translate those sections into your primary page language. This becomes clear when you click the "Preview your page" link on the official wizard.
If you look at the generated markup you will see that you mark up sections of the page something like this:
<div class="goog-trans-section" lang="zh-CN">
...content in Chinese...
</div>
The script then automatically appends a "Translate" link which allows you to translate this text back into English.
To achieve what I wanted (and what I guess you were trying to do too) I needed to stick to the "entire webpage" snippet but add a class of notranslate to anything that I didn't want to be translated.

Resources