Dom-If not refreshing after variable changes - polymer

I have this problem where, in a page from the polymer starter kit I set a variable to true, but a Dom-if created in the main app isn't re-rendered, though if I display the variable in plain, it changes.
Here's the code of the dom-if:
<app-location route="{{route}}" url-space-regex="^[[rootPath]]">
</app-location>
<app-route route="{{route}}" pattern="[[rootPath]]:page" data="{{routeData}}" tail="{{subroute}}">
</app-route>
<app-drawer-layout fullbleed="" narrow="{{narrow}}">
<!-- Drawer content -->
<template is=dom-if if='{{isLoggedIn}}'>
<app-drawer id="drawer" slot="drawer" swipe-open="[[narrow]]">
<app-toolbar class="menu">Menu</app-toolbar>
<iron-selector selected="[[page]]" attr-for-selected="name" class="drawer-list" role="navigation">
<a class="textMenu" name="view1" href="[[rootPath]]view1">3Deseos</a>
<a class="textMenu" name="login" href="[[rootPath]]login">Regalar</a>
<a class="textMenu" name="view3" href="[[rootPath]]view3">Mi Perfil</a>
</iron-selector>
<img class="fondoDeTres" src="./images/background.png">
</app-drawer>
</template>
<template is=dom-if if='{{!isLoggedIn}}'>
<app-drawer id="drawer" slot="drawer" swipe-open="[[narrow]]">
<app-toolbar class="menu">Menu</app-toolbar>
<iron-selector selected="[[page]]" attr-for-selected="name" class="drawer-list" role="navigation">
<a class="textMenu" name="view1" href="[[rootPath]]view1">3Deseos</a>
<a class="textMenu" name="login" href="[[rootPath]]login">Ingresar</a>
</iron-selector>
<img class="fondoDeTres" src="./images/background.png">
</app-drawer>
</template>
and here it's the code of the boolean (I even tried adding an observer, but it doesn't work):
isLoggedIn: {
type: Boolean,
value: false,
notify: true,
observer: '_loginStatusChanged'
}
here it's the observer:
_loginStatusChanged(status){
this.isLoggedIn=status;
console.log("Cambio el Login a "+status);
}
and the script that modifies it:
submit(){
console.log("requestSent");
var xhr = new XMLHttpRequest();
var url = "http://localhost:3000/api/login";
var request = {
username : this.username,
password : this.password
}
var that=this;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var reply = JSON.parse(xhr.responseText);
console.log(reply);
that.set('isLoggedIn', reply);
console.log(that.isLoggedIn);
}
};
var data = JSON.stringify({request});
xhr.send(data);
}
Any tips? Thanks in advance!

I solve this with iron-localstorage. I don't know if it's the best way, but ITS WORKING! :D

Related

Can we use jquery in VUE.js

Hello guys i am a newbie to Vue.js My simple question is that can we use jquery in VUE.js. because some of my jquery script like addclasses or remove classes and sidemenu script i made that into jquery and want to use that if it is possible then let me know.
just want to run simple jquery function into vue.js
My Navbar Components
<template>
<div>
<b-navbar class="navbars" toggleable="lg" type="dark" variant="info">
<router-link to="/"><b-navbar-brand href="/" v-on:click="clickme()">Home</b-navbar-brand></router-link>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<router-link to="/contact"><b-nav-item href="/contact">contact</b-nav-item></router-link>
<b-nav-item href="#" disabled>Disabled</b-nav-item>
</b-navbar-nav>
<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto">
<b-nav-form>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
<b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
</b-nav-form>
<b-nav-item-dropdown text="Lang" right>
<b-dropdown-item href="#">EN</b-dropdown-item>
<b-dropdown-item href="#">ES</b-dropdown-item>
<b-dropdown-item href="#">RU</b-dropdown-item>
<b-dropdown-item href="#">FA</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item-dropdown right>
<!-- Using 'button-content' slot -->
<template v-slot:button-content>
<em>User</em>
</template>
<b-dropdown-item href="#">Profile</b-dropdown-item>
<b-dropdown-item href="#">Sign Out</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
</div>
</template>
MY MAIN .JS I have also external file of script.js which I imported here
import Vue from vue
import App from ./App
import router from ./router
import { BootstrapVue, IconsPlugin } from bootstrap-vue
import bootstrap/dist/css/bootstrap.css
import bootstrap-vue/dist/bootstrap-vue.css
//import $ from 'jquery
window.$ = require('jquery')
window.JQuery = require('jquery')
require('#/assets/style.css')
require('#/assets/script.js')
// Install BootstrapVue
Vue.use(BootstrapVue)
// Optionally install the BootstrapVue icon components plugin
Vue.use(IconsPlugin)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
MY script.js file which is in assets
import $ from 'jquery'
$(window).on('scroll', () => {
if ($(this).scrollTop() > 100) { // Set position from top to add class
$('.navbars').addClass('header-appear');
}
else {
$('.navbars').removeClass('header-appear');
}
});
I Don't get any error but script is also not working
The issue with is the arrow function or what you expect this to be which is undefined in your code.
JQuery Fix
import $ from 'jquery'
$(window).on('scroll', function() {
if ($(this).scrollTop() > 100) { // Set position from top to add class
$('.navbars').addClass('header-appear');
}
else {
$('.navbars').removeClass('header-appear');
}
});
This is pretty easy to replicate with Vue and vanilla js so it would suggest this rather than JQuery.
<template>
...
<b-navbar :class="{'header-appear': activateClass }" class="navbars" toggleable="lg" type="dark" variant="info">
...
</template>
<script>
export default {
name: "App",
data() {
return {
activateClass: false,
};
},
created() {
window.addEventListener('scroll', this.onScroll)
},
beforeDestroy() {
window.removeEventListener('scroll', this.onScroll);
},
methods: {
onScroll() {
if (window.scrollY > 150) {
this.activateClass = true;
} else {
this.activateClass = false;
}
}
}
};
</script>

How to addEventListener to Polymer 2.0 iron-forms loaded with iron-ajax within dom-repeat template

I have been using the following syntax to edit iron-form requests before submitting in Polymer 2.0:
connectedCallback() {
super.connectedCallback();
someForm.addEventListener('iron-form-presubmit, function() {...})
}
Now I want to load multiple iron-forms within a dom-repeat, each with the same iron-form-presubmit function. The number and content of the forms are loaded from the server using iron-ajax. I intended to loop through all the forms and add the event listener but it seems when I call the following, the forms have not yet loaded so allForms is empty.
HTML:
<iron-ajax auto
id="requestSchedules"
url="/api/v2/schedules"
handle-as="json"
on-response="handleApiResponse"
last-response="{{schedules}}">
</iron-ajax>
<dom-repeat items="[[schedules]]">
<template>
<paper-card heading="Schedule">
<div class="card-content">
<iron-form id="scheduleForm[[item.id]]">
...
Javascript:
connectedCallback() {
super.connectedCallback();
var allForms = this.shadowRoot.querySelectorAll("iron-form");
// here allForms = []
...
}
Inspecting the shadow DOM with a break-point at this point shows the dom-repeat template has not loaded. Is there a way I can wait until the page has completed loading or possibly another way to accomplish the same thing?
You could listen to <dom-repeat>'s dom-change event, which occurs when the template contents change. The event handler could then use querySelectorAll to get a reference to the <iron-form>s:
template:
<dom-repeat on-dom-change="_onDomRepeatChange">
script:
_onDomRepeatChange(e) {
const forms = this.shadowRoot.querySelectorAll('iron-form');
Array.from(forms).forEach(form => {
form.addEventListener('iron-form-presubmit', function() {
this.request.method = 'post';
this.request.params['foo'] = true;
});
});
}
window.addEventListener('WebComponentsReady', () => {
class XFoo extends Polymer.Element {
static get is() { return 'x-foo'; }
_onDomRepeatChange(e) {
const forms = this.shadowRoot.querySelectorAll('iron-form');
Array.from(forms).forEach(form => {
form.addEventListener('iron-form-presubmit', function() {
this.request.method = 'post';
this.request.params['foo'] = true;
});
form.addEventListener('iron-form-response', e => {
const response = e.detail.response;
this.formResponse = JSON.stringify(response, null, 2);
});
});
}
}
customElements.define(XFoo.is, XFoo);
});
<head>
<base href="https://cdn.rawgit.com/download/polymer-cdn/2.6.0.2/lib/">
<script src="webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-ajax/iron-ajax.html">
<link rel="import" href="iron-form/iron-form.html">
<link rel="import" href="paper-card/paper-card.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<iron-ajax auto
id="requestSchedules"
url="https://httpbin.org/anything"
method="POST"
handle-as="json"
content-type="application/json"
body='[{"id":1, "x":1},{"id":2, "x":2}]'
last-response="{{schedules}}">
</iron-ajax>
<template is="dom-repeat" items="[[schedules.json]]" on-dom-change="_onDomRepeatChange">
<paper-card heading="Schedule">
<div class="card-content">
<iron-form id="scheduleForm[[item.id]]">
<form action="https://httpbin.org/post">
<input name="name" type="text" placeholder="Name">
<button>Submit</button>
</form>
</iron-form>
</div>
</paper-card>
</template>
<pre>[[formResponse]]</pre>
</template>
</dom-module>
</body>
Alternatively, you could use an annotated event listener on <iron-form>:
template:
<iron-form on-iron-form-presubmit="_onIronFormPresubmit">
script:
_onIronFormPreSubmit(e) {
const ironForm = e.composedPath()[0];
ironForm.request.method = 'post';
ironForm.request.params['foo'] = true;
}
window.addEventListener('WebComponentsReady', () => {
class XFoo extends Polymer.Element {
static get is() { return 'x-foo'; }
_onIronFormPreSubmit(e) {
const ironForm = e.composedPath()[0];
ironForm.request.method = 'post';
ironForm.request.params['foo'] = true;
}
_onIronFormResponse(e) {
const response = e.detail.response;
this.formResponse = JSON.stringify(response, null, 2);
}
}
customElements.define(XFoo.is, XFoo);
});
<head>
<base href="https://cdn.rawgit.com/download/polymer-cdn/2.6.0.2/lib/">
<script src="webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-ajax/iron-ajax.html">
<link rel="import" href="iron-form/iron-form.html">
<link rel="import" href="paper-card/paper-card.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<iron-ajax auto
id="requestSchedules"
url="https://httpbin.org/anything"
method="POST"
handle-as="json"
content-type="application/json"
body='[{"id":1, "x":1},{"id":2, "x":2}]'
last-response="{{schedules}}">
</iron-ajax>
<template is="dom-repeat" items="[[schedules.json]]">
<paper-card heading="Schedule">
<div class="card-content">
<iron-form id="scheduleForm[[item.id]]"
on-iron-form-presubmit="_onIronFormPreSubmit"
on-iron-form-response="_onIronFormResponse">
<form action="https://httpbin.org/post">
<input name="name" type="text" placeholder="Name">
<button>Submit</button>
</form>
</iron-form>
</div>
</paper-card>
</template>
<pre>[[formResponse]]</pre>
</template>
</dom-module>
</body>

Access current item when clicking link in dom-if inside dom-repeat

I have the following template:
<template is="dom-repeat" items="{{myItems}}">
<template is="dom-if" if="{{_shouldHaveLink(item)}}">
Link
</template>
</template>
Now, if the link was not wrapped in a dom-if, I can see the item which was pressed with:
_linkTapped: function (oEvent) {
console.log('Item link tapped:', oEvent.model.get('item'));
}
But inside the dom-if I can't. Seems like item is now out of scope. How can I get it?
This is a known bug with Polymer's dom-repeat yet to be solved, but there's a simple workaround in this scenario.
Since the dom-if template without restamp simply hides its contents when the if condition is false (as an optimization), you could simulate the original behavior while avoiding the dom-if-related bug by replacing the template with a hidden attribute based on the same condition negated:
<div hidden$="{{!_shouldHaveLink(item)}}">
Link
</div>
or:
Link
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
properties: {
items: {
type: Array,
value: () => [
{ name: 'google', link: 'http://www.google.com' },
{ name: 'facebook' },
{ name: 'twitter', link: 'http://www.twitter.com' },
]
}
},
_hasNoLink: function(item) {
return !item.link;
},
_linkTapped: function(e) {
console.log(e.model.item);
// for demo only...
e.preventDefault();
}
});
});
<head>
<base href="https://polygit.org/polymer+1.7.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<div>Facebook anchor is hidden because it has no link</div>
<template is="dom-repeat" items="[[items]]">
<a href="#"
hidden$="{{_hasNoLink(item)}}"
on-tap="_linkTapped">[[item.name]]</a>
</template>
</template>
</dom-module>
</body>
codepen
And as #DocDude suggested, another alternative is to use <dom-repeat>.modelForElement(e.target) if you have a reference to the <dom-repeat>:
//template
<template id="repeater" is="dom-repeat" items="[[items]]">
// script
_linkTapped: function(e) {
const m = this.$.repeater.modelForElement(e.target);
console.log(m.item);
...
}
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
properties: {
items: {
type: Array,
value: () => [
{ name: 'google', link: 'http://www.google.com' },
{ name: 'facebook' },
{ name: 'twitter', link: 'http://www.twitter.com' },
]
}
},
_hasLink: function(item) {
return item.link;
},
_linkTapped: function(e) {
const m = this.$.repeater.modelForElement(e.target);
console.log(m.item);
// for demo only...
e.preventDefault();
}
});
});
<head>
<base href="https://polygit.org/polymer+1.3.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<div>Facebook anchor is hidden because it has no link</div>
<template id="repeater" is="dom-repeat" items="[[items]]">
<template is="dom-if" if="{{_hasLink(item)}}">
[[item.name]]
</template>
</template>
</template>
</dom-module>
</body>
codepen

Polymer, how to format a URL string w/ a variable

I want to binding a URL string like this:
like
but it not work.
what should i do?
<dom-module id="list-view">
<template id="app" testattr$="{{value}}" >
<iron-list id="list" items="{{data}}" as="item">
<template>
<a href="{{item.id}}" >
<span>[[item.name]]</span>
</a>
</template>
</iron-list>
</template>
<script>
Polymer({
is: 'list-view',
ready: function() {
var _self = this;
$.get('data/persons.json',function(data){
_self.data =
});
});
});
</script>
</dom-module>
I use iron-list element to repeat the data to list. object --> [{"id":"001","name":"adisak"},{"id":"002","name":"adisak2"},{"id":"003","name":"‌​adisak3"}] then i use iron-list to binding data in to list of element
You can compute your URL with a method, like this:
<dom-module id="list-view">
<template id="app" testattr$="{{value}}" >
<iron-list id="list" items="{{data}}" as="item">
<template>
<a href="{{_computeUrl(item.id)}}" >
<span>[[item.name]]</span>
</a>
</template>
</iron-list>
</template>
<script>
Polymer({
is: 'list-view',
ready: function() {
var _self = this;
$.get('data/persons.json',function(data){
_self.data = data;
});
},
_computeUrl: function(id) {
return '/myurl/' + id;
}
});
</script>

Best Way to Save Editing State in My Ember.js Application

I have spent the last few days monkeying with my app, trying to figure out how best to keep track of an editing state within a given controller. Of course, the problem is, multiple of these ObjectControllers exist at one time, and only one can be editing at a given moment. Below is the important code:
App.js:
var App = Ember.Application.create();
//ROUTES
App.Router.map(function() {
this.resource('tasks', function() {
this.resource('task', {path: ':task_id'});
});
});
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('tasks');
}
});
App.TasksRoute = Ember.Route.extend({
model: function() {
return App.Task.find();
}
});
App.TaskRoute = Ember.Route.extend({});
//CONTROLLERS
App.TasksController = Ember.ArrayController.extend({
isEditing: null,
editing: false,
newTask: function() {
console.log('new task');
},
toggleEdit: function(id) {
this.set('isEditing', id);
if ($('#collapse' + this.get('isEditing')).hasClass('in')) {
this.set('editing', false);
this.set('isEditing', null);
$('.in').collapse('hide');
} else {
this.set('editing', true);
$('.in').collapse('hide');
$('#' + 'collapse' + this.get('isEditing')).collapse('toggle');
}
}
});
App.TaskController = Ember.ObjectController.extend({
needs: 'tasks',
collapseId: function() {
return "collapse" + this.get('id');
}.property('id'),
collapseHref: function() {
return "#collapse" + this.get('id');
}.property('id'),
});
//VIEWS
App.ApplicationView = Ember.View.extend({
didInsertElement: function() {
var self = this;
Ember.run.schedule('afterRender', function() {
self.$('.navbar').affix({offset: -1000});
});
}
});
//HANDLEBARS HELPERS
//STORE DEFINITION
App.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.FixtureAdapter'
/*DS.RESTAdapter.extend({
url: 'http://localhost:3000'
})*/
});
//MODELS
App.Task = DS.Model.extend({
summary: DS.attr('string'),
description: DS.attr('string'),
start: DS.attr('string'),
end: DS.attr('string'),
recurrence: DS.attr('string')
});
//FIXTURE DATA
App.Task.FIXTURES = [{
id: "q5ji9chrh1hcu05dohvrf4aumc",
summary: "Test",
description: null,
start: "2013-04-01T10:00:00-07:00",
end: "2013-04-01T11:00:00-07:00",
recurrence: "FREQ=WEEKLY;BYDAY=MO,WE,TH,FR"
}, {
id: "mm4m3pq6icbgbl6m49jpdhi8j0",
summary: "Test 2",
description: "absafdaerwer",
start: "2013-04-01",
end: "2013-04-02",
recurrence: null
}];
Home.HTML:
<!--TEMPLATES-->
<script type="text/x-handlebars">
<div class="navbar" data-spy="affix">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
</div>
</div>
</div>
{{outlet}}
</script>
<script type="text/x-handlebars" id="tasks">
<div class="row-fluid span8 offset2 task-list">
<div class="space-top"><div>
<div class="accordion" id="accordion">
{{partial 'tasks/newTask'}}
{{#each task in controller}}
<div class="accordion-group">
{{render 'task' task}}
</div>
{{/each}}
</div>
</div>
</script>
<script type="text/x-handlebars" id="tasks/_newTask">
<div class="accordion-group">
<div class="new-task-header accordion-heading" {{action newTask on="click"}}>
<span class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapseNew">New Task...</span>
</div>
<div id="collapseNew" class="accordion-body collapse">
<div class="new-task accdion-inner">
{{#if task.description}}
<p>{{task.description}}</p>
{{else}}
<p>No description</p>
{{/if}}
</div>
</div>
</div>
</script>
<script type="text/x-handlebars" id="task">
<div class="task">
{{#linkTo 'task' task}}
<div class="accordion-heading" {{action toggleEdit task.id on="click"}}>
<span class="accordion-toggle" data-toggle="collapse" data-parent="#accordion">
{{#if controllers.tasks.editing}}
editing {{task.summary}}
{{else}}
{{task.summary}}
{{/if}}
</span>
</div>
{{/linkTo}}
</div>
<div {{bindAttr id="collapseId"}} class="accordion-body collapse">
<div class="edit-task accdion-inner">
{{#if task.description}}
<p>{{task.description}}</p>
{{else}}
<p>No description</p>
{{/if}}
</div>
</div>
</script>
In this code, there are not multiple TaskControllers being created, I believe. Try setting itemController: 'task' on the ArrayController. (Discussed here, and if you're using 1.0.0-rc.2 see mention here.) That way you can set an editing property on that particular task (and reference tasks if needed). Does that clear anything up?