Can't print value from array of objects - vue.js

Here I am filling the localStorage:
let storageObj = {};
storageObj.date = (new Date().toLocaleString().replace(", ","T"));
storageObj.url = this.responseURL;
localStorage.setItem(storageObj.date, storageObj.url);
In mounted() I am iterate all data from localStorage like:
for(let obj of Object.entries(localStorage))
{
this.lastpasts.push(obj);
}
And placing every Object to lastpasts (located in data() {lastpasts : []}).
In template I want to print only url:
<div class="ui divided items" v-for="el in lastpasts">
<div class="item">
{{el.url}}
</div>
</div>
But this code do not print nothing. Work only {{el}}. It's print in HTML block:
[ "24.06.2017T11:55:10", "362e9cc5-e7e6" ]
[ "24.06.2017T12:26:47", "b0f9f20d-7851" ]
Browser console do not have any errors.

In the chat session we managed to solve his issue.
It was caused by the fact, that he was using Array of Arrays instead of Array of Objects. Because Array can be used only with index, not field name, {{el.url}} was not working.
The code to get values from LocalStorage had to be changed to:
mounted() {
for(let obj of Object.entries(localStorage)) {
var x = {};
x.url = obj[0];
x.date = obj[1];
this.lastpasts.push(x);
}
}
Now, it is possible to use {{el.url}}

Related

Why this odd warning from Vue / Vuetify / Vite?

I am constructing an array of Vuetify 'chips' that can have data dragged from one to the other:
<v-container id="endgrid" style="max-width: 300px; position: relative;">
<v-row v-for="(row,r) in endGrid">
<v-chip size="x-large"
v-for="(chip,c) in row"
:key="chip.name"
draggable="true"
#drop="drop($event)"
#dragover="allowDrop($event)"
#dragstart="drag($event)"
:id=idString(1,r,c)
> {{ chip.name }} </v-chip>
</v-row>
</v-container>
and it works as expected. But during the document creation I am getting this warning (in the debug console) for every one (of 25) chip creations:
[Vue warn]: Invalid prop: type check failed for prop "draggable". Expected Boolean, got String with value "true".
at <VChip size="x-large" key=43 draggable="true" ... >
I'm sure the correct syntax for draggable is with a string, not a Boolean. Although if I remove the quotes, the warnings still appear - but the code still works.
I'm concerned that
this may be hiding something else wrong in my code
even if not, those warnings appearing in a browser's debug console don't look good!
Since it may be relevant, the data used to construct the grid looks like this:
onBeforeMount(() => {
var index = 1;
for (var i = 0; i < 5; i++)
{
endGrid[i] = [];
for (var j = 0; j < 5; j++)
{
endGrid[i][j] = {
"name" : i*10+j,
"id" : index,
"row" : i,
"col" : j,
"list": 'end'
};
++index;
}
}
});
You need to bind draggable first in order to pass boolean:
:draggable="true"

D3 linkHorizontal() update on mouse position

I’m trying to implement a drag and drop functionality with a connection line. The connection line has a starting point ([x, y]), which is gathered when the mouse is clicked and a target point ([x, y]) which follows the mouse position and is continuously updated while dragging the element.
The project uses Vue.JS with VUEX store and for the connection line D3.js (linkHorizontal method https://bl.ocks.org/shivasj/b3fb218a556bc15e36ae3152d1c7ec25).
In the main component I have a div where the SVG is inserted:
<div id="svg_lines"></div>
In the main.js File I watch the current mouse position (targetPos), get the start position from the VUEX store (sourcePos) and pass it on to connectTheDots(sourcePos, targetPos).
new Vue({
router,
store,
render: (h) => h(App),
async created() {
window.document.addEventListener('dragover', (e) => {
e = e || window.event;
var dragX = e.pageX, dragY = e.pageY;
store.commit('setConnMousePos', {"x": dragX, "y": dragY});
let sourcePos = this.$store.getters.getConnStartPos;
let targetPos = this.$store.getters.getConnMousePos;
// draw the SVG line
connectTheDots(sourcePos, targetPos);
}, false)
},
}).$mount('#app');
The connectTheDots() function receives sourcePos and targetPos as arguments and should update the target position of D3 linkHorizontal. Here is what I have:
function connectTheDots(sourcePos, targetPos) {
const offset = 2;
const shapeCoords = [{
source: [sourcePos.y + offset, sourcePos.x + offset],
target: [targetPos.y + offset, targetPos.x + offset],
}];
let svg = d3.select('#svg_lines')
.append('svg')
.attr('class', 'test_svgs');
let link = d3.linkHorizontal()
.source((d) => [d.source[1], d.source[0]])
.target((d) => [d.target[1], d.target[0]]);
function render() {
let path = svg.selectAll('path').data(shapeCoords)
path.attr('d', function (d) {
return link(d) + 'Z'
})
path.enter().append('svg:path').attr('d', function (d) {
return link(d) + 'Z'
})
path.exit().remove()
}
render();
}
I stole/modified the code from this post How to update an svg path with d3.js, but can’t get it to work properly.
Instead of updating the path, the function just keeps adding SVGs. See attached images:
Web app: Multiple SVGs are drawn
Console: Multiple SVGs are added to element
What am I missing here?
#BKalra helped me solve this.
This line keeps appending new SVGs:
let svg = d3.select('#svg_lines') .append('svg') .attr('class', 'test_svgs');
So I removed it from the connectTheDots() function.
Here is my solution:
In the main component I added an SVG with a path:
<div id="svg_line_wrapper">
<svg class="svg_line_style">
<path
d="M574,520C574,520,574,520,574,520Z"
></path>
</svg>
</div>
In the connectTheDots() function I don't need to append anymore, I just grap the SVG and update its path:
function connectTheDots(sourcePos, targetPos) {
const offset = 2;
const data = [{
source: [sourcePos.y + offset, sourcePos.x + offset],
target: [targetPos.y + offset, targetPos.x + offset],
}];
let link = d3.linkHorizontal()
.source((d) => [d.source[1], d.source[0]])
.target((d) => [d.target[1], d.target[0]]);
d3.select('#svg_line_wrapper')
.selectAll('path')
.data(data)
.join('path')
.attr('d', link)
.classed('link', true)
}

Using document.getElementsByClassName in Testcafe

I have a menu that always has the same structure, but the IDs can change from one installation to another. the only thing that stays the same is the heading (in my case "Plugins"). I call the document.getElementsByClassName function with a Selector inside my test:
var slides = Selector(() =>{
return document.getElementsByClassName("c-p-header-text");
});
Every heading of an menu element has the c-p-header-text class. Here is what a menu heading element looks like:
<div id="ext-comp-1002" class="c-p c-tree c-p-collapsed" style="width: auto;">
<div class="c-p-header c-unselectable c-accordion-hd" id="ext-gen135" style="cursor: pointer;">
<div class="c-tool c-tool-toggle" id="ext-gen140"> </div>
<img src="/backEnd/images/s.gif" class="c-p-inline-icon order"><span class="c-p-header-text" id="ext-gen150">Plugins</span>
</div>
It would be easy to use await t.click("#ext-gen150") but it is not safe that it is always this id.
here is what i tried:
await t
.click('#sites__db');
var slides = Selector(() =>{
return document.getElementsByClassName("c-p-header-text");
});
console.log("[DEBUG]" + slides);
console.log("[DEBUG] found " + slides.length + " elements");
for(var i = 0; i < slides.length; i++)
{
var txtOfCurrElem = slides.item(i).innerText;
console.log("[DEBUG "+ i +"] Text: " + txtOfCurrElem);
}
Running this test give me the following output:
[DEBUG]function __$$clientFunction$$() {
var testRun = builder.getBoundTestRun() || _testRunTracker2.default.resolveContextTestRun();
var callsite = (0, _getCallsite.getCallsiteForMethod)(builder.callsiteNames.execution);
var args = [];
// OPTIMIZATION: don't leak `arguments` object.
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}return builder._executeCommand(args, testRun, callsite);
}
[DEBUG] found 0 elements
The plan is to find the element (with the heading "Plugins") and then click on it when the test continuous.
You don't have to use document.getElementsByClassName in this case. You can just use CSS class selector instead:
var slides = Selector('.c-p-header-text');
You should use the count property when dealing with an array of Selectors. docs. Also, element properties, like exists, count, and DOM node state properties are Promisified, so when you use them not in t.expect, you should use the await keyword:
var count = await slides.length;
console.log("[DEBUG] found " + count + " elements");
for(var i = 0; i < count; i++)
{
var txtOfCurrElem = await slides.nth(i).innerText;
console.log("[DEBUG "+ i +"] Text: " + txtOfCurrElem);
}
I found a simple answer to my question. I use the .withText option to click on the Plugins element:
.click(Selector('span').withText("Plugins"))
Since this name is also unique, it is always the correct element that gets clicked. I do not know if it would have worked with the solution from #AndreyBelym if my site is not an extJS web application.

vendor prefix pseudo-selector crashes element.matches() Web API in Safari

I'm building a utility into a style guide generator that automatically gathers the CSS for each element and displays it adjacent to the element in the output. The script I'm using to gather and parse the CSS is based on an answer from SO and uses the element.matches() web API.
Under most circumstances the code works perfectly, but in cases where there is a 'vendor prefix'-specific pseudo-element selector (e.g. ::-webkit-inner-spin-button as in Bootstrap 4.0), Safari throws an error at the most nested if statement (i.e. if (a.matches(rules[r].selectorText)) {):
SyntaxError (DOM Exception 12): The string did not match the expected pattern.
I've tried searching for this error specifically on SO and I found this question that talks about missing array endings, but I don't think the answer pertains to my issue.
I have a regex workaround that will remove the offending rules so the function can at least run, but as you can see, the properties in that rule ({background-color:black;}) are completely ignored in the output even though they're applied to the rendered element.
I could modify my regex to parse the strings and slice out problematic selectors while leaving the parsable rules, but overall this type of very specific hack feels inelegant to me, and I'm concerned it may cause problems down the road if my team ends up adding rules that rely on those types of vendor-prefixed pseudo-selectors.
Any ideas on how I can be a little more precise about working around (or solving) this issue?
Working Snippet
window.css = function (a) {
var sheets = document.styleSheets, o = [];
a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector;
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
if (a.matches(rules[r].selectorText)) {
o.push(rules[r].cssText);
}
}
}
return o;
}
$(document).ready(function(){
$('button').on('click',function(){
$('#styles').text(css( $( $('input').val() )[0] ));
});
});
div * {border-left:2px solid black;margin:1em 0;padding:.5em;}
a {text-decoration:none;display:block;cursor:pointer;}
#red {color:red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="#red"><button>Get styles</button>
<div>
<a id="red">#red anchor</a>
</div>
<aside id="styles"></aside>
Broken Snippet
(only change is 1 added line of CSS)
window.css = function (a) {
var sheets = document.styleSheets, o = [];
a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector;
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
if (a.matches(rules[r].selectorText)) {
o.push(rules[r].cssText);
}
}
}
return o;
}
$(document).ready(function(){
$('button').on('click',function(){
$('#styles').text(css( $( $('input').val() )[0] ));
});
});
div * {border-left:2px solid black;margin:1em 0;padding:.5em;}
a {text-decoration:none;display:block;cursor:pointer;}
#red {color:red;}
/* v ADDED THIS LINE - THIS IS THE ONLY CHANGE v */
[type="submit"]::-webkit-inner-spin-button {background-color:black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="#red"><button>Get styles</button>
<div>
<a id="red">#red anchor</a>
</div>
<aside id="styles"></aside>
Reg-Ex Workaround
window.css = function (a) {
var sheets = document.styleSheets, o = [];
a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector;
// v NEW FUNCTION v
function removeVendorPrefixSelectors (selectorText) {
if (/::-/.test(selectorText)) {
//do nothing
} else {
return selectorText;
}
}
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
// v NEW LINE v
rule = removeVendorPrefixSelectors(rules[r].selectorText);
if (a.matches(rule)) {
o.push(rules[r].cssText);
}
}
}
return o;
}
$(document).ready(function(){
$('button').on('click',function(){
$('#styles').text(css( $( $('input').val() )[0] ));
});
});
div * {border-left:2px solid black;margin:1em 0;padding:.5em;}
a {text-decoration:none;display:block;cursor:pointer;}
#red {color:red;}
a, [type="submit"]::-webkit-inner-spin-button {background-color:black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="#red"><button>Get styles</button>
<div>
<a id="red">#red anchor</a>
</div>
<aside id="styles"></aside>

How to create SwapView dynamically using Dojo

I am using Dojo v1.8 with Worklight; I would like create a SwapView dynamically in View, but I'm encountering problems...
HTML code:
<div data-dojo-type="dojox.mobile.View" id="listeInscriptionView"
data-dojo-props="selected:false,scrollDir:'vh'"
style="background-image: url('images/bg-texture.jpg');"
data-dojo-id="id">
</div>
JavaScript code:
var view = registry.byId(listeInscriptionView);
alert(view);
for(var i = 1; i < 3; i++ ){
var swap = new dojox.mobile.SwapView({
id: i,
selected:false
});
var head = new dojox.mobile.Heading({
label:'Swap' + i,
});
swap.addChield(head);
view.addChield(swap);
alert("test" + i);
}
The above does not work. How I can create the widget SwapView dynamically?
Is that a copy of your actual code? I have not actually tested it but there are syntax errors and typos:
registry.byId(listeInscriptionView);
should be
registry.byId("listeInscriptionView");
(missing quotes), and
swap.addChield(head);
view.addChield(swap);
should be
swap.addChild(head);
view.addChild(swap);
Maybe it works better with these errors fixed?