Polymer 1.0 Data binding when object changes - migration

I'm having trouble understanding how data-binding works now.
On my index page I've got an object (obtained as JSON from a RESTful service), which works just fine when applied to a custom element like:
<main-menu class="tiles-container ofvertical flex layout horizontal start"
menuitems="{{menuitems}}">
</main-menu>
var maintemplate = document.querySelector('#fulltemplate');
maintemplate.menuitems = JSON.parse(data.GetDesktopResult);
This works as expected, and when I load my page with different users, main-menu changes as it should to show each user's desktop configuration. (This menuitems object reflects position and size of each desktop module for each user).
Now, users used to be able to change their configuration on the go, and on Polymer 0.5 I had no problem with that, just changed my maintemplate.menuitems object and that was that, it was reflected on the template instantly.
As I migrated to Polymer 1.0, I realized changes on an object wouldn't change anything visible, it's much more complicated than this, but just doing this doesn't work:
<paper-icon-button id="iconback" icon="favorite" onClick="testing()"></paper-icon-button>
function testing(){
debugger;
maintemplate = document.querySelector('#fulltemplate');
maintemplate.menuitems[0][0].ModuleSize = 'smamodule';
}
The object changes but nothing happens on the screen until I save it to DB and reload the page.
Am I missing something /Do I need to do something else on Polymer 1.0 to have elements update when I change an object passed as a property?
Before you ask, I've got those properties setted as notify: true, it was the inly thing I found different, but still doesn't work
Thanks for reading!
EDIT:
this is the code menuitems is used in:
<template is="dom-repeat" items="{{menuitems}}" as="poscol">
<div class="positioncolum horizontal layout wrap flex">
<template is="dom-repeat" items="{{poscol}}" as="mitem" index-as="j">
<main-menu-item class$="{{setitemclass(mitem)}}"
mitem="{{mitem}}"
index="{{mitem.TotalOrder}}"
on-click="itemclick"
id$="{{setitemid(index, j)}}">
</main-menu-item>
</template>
</div>
</template>
main-menu-item is just set of divs which changes size and color based on this object properties

You need to use the mutation helper functions if you want to modify elements inside an object or array otherwise dom-repeat won't be notified about the changes (check the docs):
function testing(){
debugger;
maintemplate = document.querySelector('#fulltemplate');
this.set('maintemplate.0.0.ModuleSize', 'smamodule');
}

Related

How to stop click propagation when clicking on a leaflet popup?

I have a popup in a leaflet map that can be closed by clicking on the 'x' in its upper right corner. How do I make the click event not propagate to the map itself?
I've tried using preventPropagate() in many places and forms, but none of them seem to work.
My latest code looks like that:
<div class="actions" #click="stopPropagation($event)">
(...)
stopPropagation(e) {
e.stopPropagation()
}
The above div (.actions) is the popup's main div.
I have also tried calling the function at a click in the popup's component tag in the parent component, but the result was the same, meaning clicking the 'x' closes the popup as expected but also results in a click event in the map that lies behind.
I use Vue and vue2-leaflet.
I appreciate any insight from you guys. Thanks!
UPDATE: actually, doesn't matter where in the popup the click happens, it always gets propagated to the map behind.
So, for reference, here's my solution:
<div class="actions" #click="someMethod($event)">
(...)
someMethod(e) {
(... some code)
return false
}
The command 'return false' is what solved my problem.
I tried using '#click.stop', but it gives me the '$event.stopPropagation() is not a function' error. The same happens if I run 'e.stopPropagation()' from inside the function.
The accepted answer didn't work for me so I wrapped my l-map in a div and applied the click.stop to that.
<div #click.stop.prevent.self="">
<l-map...>
</div>
It seems to me that the actual click event is parsed by the leaflet library rather than the Vue-compatible vue-2-leaflet, so the event that is received by the function doesn't have stopPropagation or preventDefault methods on the object. Thus, when Vue calls them with .stop or .prevent, the JS engine throws an error.
This is what I figured out for my issue dealing with event handling and stopping the propagation.
e.g.
someReference.on("click", (evt: L.LeafletEvent) => {
// You don't try to reference the event (evt) that is passed in
L.DomEvent.stopPropagation; // Just call this and it kills the propagation
// or you can call
// L.DomEvent.preventDefault(evt);
...
})
Could try an event modifier
Perhaps the stop modifier:
<div class="actions" #click.stop="closePopup">

Vuetify breakpoints not working in Nuxt.js

I'm working on a project using Nuxt.js as SSR engine and Vuetify as styling framework. In one of my templates I have such code:
<v-layout row wrap align-center
:class="{ 'mb-4': $vuetify.breakpoint.smAndDown }">...</v-layout>
As you can see, I want to apply mb-4 class only if I am on small screens and smaller ones. But when I load this on desktop large screen and inspect element, this class is attached even though screen resolution does not match logic for applying this class. However, styling is back to expected when I resize browser window.
I've tried to manually dispatch 'resize' event in lifecycle hook:
mounted() {
window.dispatchEvent(new Event('resize'));
}
But it didn't help. Even if I wrap it in setTimeout, still no luck.
UPD: found a workaround, but still think it is not the best solution:
changed
:class="{ 'mb-4': $vuetify.breakpoint.smAndDown }"
to
:class="{ 'mb-4': isMounted && $vuetify.breakpoint.smAndDown }"
and in mounted lifecycle hook added: this.isMounted = true
UPDATE: while digging in Vuetify source code found out, that it checks window width with 200ms delay as window width check is costly operation. That is why we have delay.
you can give specific breakpoint for margin and padding attributes.
<v-layout row wrap align-center class="mb-sm-4">...</v-layout>
https://vuetifyjs.com/en/styles/spacing/#breakpoints

Positioning based on size of rendered component

I have a Vue component which generates a part of an SVG.
Since text handling in SVG is a pain, I decided to use a foreignObject tag inside it in order to let the HTML and CSS inside it handle the layout.
The template part basically looks like this:
<template>
<g class="port">
<foreignObject ref="html">
<div class="port__wrapper" ref="wrapper">
<div class="port__label">{{ label }}</div>
<div class="port__content">{{ content }}</div>
</div>
</foreignObject>
</g>
</template>
Everything works fine until I try to position the part, based on its computed size. The size of my foreignObject has to be set manually. In order to do that, I need the computed size of my port__wrapper element.
Here is my current approach:
export default {
methods: {
calculateAndSetSize() {
const frame = this.$refs.html;
const wrapper = this.$refs.wrapper;
frame.setAttribute('width', `${wrapper.clientWidth}px`);
frame.setAttribute('height', `${wrapper.clientHeight}px`);
}
},
created() {
window.setTimeout(() => {
this.calculateAndSetSize();
// also some positioning stuff
}, 0);
}
}
I use the created lifecycle hook to ensure the component is created and use the setTimeout to move the calculation to the end of the render queue.
This works fine when I just move around inside my app, but if I refresh the page it only works 5/6 of the time. The calculation seems to be done just before the final render.
An example from Safari (even though it happens in all browsers):
I captured this, while my system was super slow. This usually happens in a fraction of a second
Before the component is fully rendered, this part is visible:
The component takes up a little bit less than double the size of the end-result. The calculation and positioning have happened and everything is aligned as expected (right side and vertically centered to the cross in the middle).
Almost correct, but then there is the final paint, which looks like this:
As you can see the positioning is totally off, since the element is way smaller and the calculations already happened.
The foreignObject sill has the wrong size:
(the last screenshot is from another build and looks a little different, but the problem stays the same)
I figured the problem might be the font loading and tried the execute the calculations after the document.fonts.ready promise, but that is even less consistent than the setTimeout approach.
Any hint what could cause this and how to work around it would be greatly appreciated.

Instantiating dijit.Dialog from a template I can't get it to initialize properly

In Dojo, I am trying to extend dijit.Dialog using templates. When I instantiate it, I get only the text in the dialog box, without the borders or close button. Is there some additional step I need to do to get it fully initialized?
My template is in template.html, it looks like so:
<div dojoType="dijit.Dialog" id="dynFilter" jsId="dynFilter">
"Dynamic Dialog"
</div>
Here is the dojo.declare:
dojo.declare(
"template.dialog", // class name
[dijit._Widget, dijit._Templated, dijit.Dialog], // parent classes
{
templateString : dojo.cache("autonomics", "template.html"),
}
);
After I instantiate it, I call .startup(), which doesn't seem to do anything, then .show(), which does place it on the page, missing most of its functionality.
var dialog = new template.dialog();
dialog.startup();
dialog.show();
What am I missing?
You overwrite the template of the original dijit/Dialog when subclassing.
Have a look to my answer to Dojo Dialog with confirmation button which solves the issue you are experiencing. Or go directly to working example at jsFiddle: http://jsfiddle.net/phusick/wkydY/

DojoX Mobile ListItem load HTML via AJAX and then remove from DOM

Let's say in a view I have a DojoX Mobile ListItem that is pulling an HTML view fragment into the DOM via AJAX and then transitioning to that view. Assume this is all working fine.
Now, I go back to the initial view that had that ListItem on it and click some other button that destroys that view node from the DOM. If I now click on that ListItem that previously loaded that view node into the DOM (which has now been removed), it will try to transition to a view that doesn't exist. It doesn't know that it has been removed.
Is there some type of way to tell a ListItem that it needs to fetch the HTML again because what was previously fetched no longer exists? I am not seeing anything about doing this in any documentation anywhere. I don't think a code sample is really necessary here, but I can provide a minimal one if necessary.
I went a different route and left the view exist in the DOM, and simply made a function that clears all sensitive data out of the view.
Okay, in this case, i guess you could hook the onShow function of your ListItem container(or any other onchange event). Create a listener for said handle to evaluate if your item needs reloading. Following is under the assumtion that it is the item.onclick contents showing - and not the label of your item which contains these informations
Or better yet, do all this during initialization so that your ListItem container will be an extended with custom onClick code.
Seems simple but may introduce some quirks, where/when/if you programatically change to this item, however here goes:
function checkItem() {
// figure out if DOM is present and if it should be
if( isLoggedIn() ) {
this.getChildren().forEach(function(listitem) {
if( dojo.query("#ID_TO_LOOK_FOR", listitem.domNode).length == 0 ) {
// this references the listItem, refresh contents.
// Note: this expects the listitem to be stateful, have no testing environment at time being but it should be
listitem.set("url", listitem.url);
}
});
}
}
Preferably, set this in your construct of the container for your ListItems
var listItemParent = new dojox.mobile.RoundRectList({
onShow : checkItem,
...
});
Or create listener
var listItemParent = dijit.byId('itemRegistryId');
// override onClick - calling inheritance chain once done
dojo.connect(listItemParent, "onClick", listItemParent, checkItem);