How to pass vue component props array of object? - json

I have a dropdown in my component and here is a json file that comes from back:
items:[
{
name:"label",
value:"",
options:[
]
},
{
name:"hint_text",
value:"",
options:[
]
},
{
name:"icon",
value:"",
options:[
]
},
{
name:"selectableOptions",
value:[
{
id:"1",
text:"item1",
},
{
id:"2",
text:"item2",
image_url:null
},
{
id:"3",
text:"item3",
image_url:null
},
{
id:"4",
text:"item4",
image_url:null
},
{
id:"5",
text:"item5",
image_url:null
},
{
]
}
]
and this is how my component looks like:
<template>
<div class="dropdown">
<div class="field">
<v-select
label="Label" // label must be eqau to items[0].name
hint="hint"//hint must be equal items[1].name
persistent-hint
background-color=""
:items="['item1', 'item2', 'item3']"// must be equal to items[3].value.text
outlined
>
<span
class=""
style="font-size:16px; color:#000000;"
slot="prepend-inner"
>icon</span>// must be equal to item[2].name
</v-select>
</div>
<script>
export default {
props: {
items: {
type: Object;
},
};
</script>
I got an error that items is not Object and it's an array but if I change to an array still doesn't work. and would you please help me, How to pass properly the items' elements which I write in the comments part?

Your JSON is not fully correct and there's something wrong with template code, but I hope it's just typos.
You can just set correct type of your prop (it should be an Array) and you'll be able to pass array of props this way:
...
<div class="dropdown">
<div>
<v-select
:label="items[0].name"
:hint="items[1].name"
persistent-hint
background-color=""
:items="items[3].value"
item-value="id"
item-text="text"
outlined
>
<span
class=""
style="font-size:16px; color:#000000;"
slot="prepend-inner"
> {{ items[2].name }} </span>
</v-select>
</div>
</div>
...
<script>
export default {
props: {
items: {
type: Array
}
}
}
</script>

Related

VUE-JS - CHECKBOX V-MODEL

enter image description here Hi Everyone Newbie at VUE.JS
I have a Checkboxes for MODULES and FUNCTIONS
I want to insert a Functions for every MODULE I have
Here's my sample code
<label> Modules:</label>
<li v-for="subModule1 in subModules" :key="subModule1.id">
<input type="checkbox" v-model="dataModules" :value="subModule1" />
{{subModule1}}<br>
[enter image description here][1]
{{subFunction}}
</div>
One thing that you could do is to create component like bellow I am not sure it will be a perfect solution but it should work atleast
<template>
<div>
<div v-for="module in modules" :key="module.text">
<h3>{{module.text}}</h3>
<ul>
<li
v-for="subModule in module.subModules"
:key="subModule.text"
>
{{subModule.text}}
<input type="checkbox" v-model="subModule.value"/>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'Example',
data(){
return {
modules:[
{
text:"Module 1",
subModules:[
{
text:"1-A",
value:false,
},
{
text:"1-b",
value:false,
}
]
},
{
text:"Module 2",
subModules:[
{
text:"2-A",
value:false,
},
{
text:"2-b",
value:false,
}
]
}
]
}
}
}
</script>
With this you are binding with array key is text but you can change it to something else and if you want to add new module or sub module just add it to array and it should be added to ui
If module dont pick new added items you something like deep copy and assign new array to module

Vue component using the <code> does not re-render on change of prop

I am making a code snippet that shows the code of a html element.
The snippet is suppose to change on press of buttons on other component.
The text displayed on snippet is passed as prop to the code snippet component.
<template>
<pre class="language-html" id="code-section">
<code>{{sourcecode}}</code>
</pre>
</template>
<script>
export default {
name: "CodeSnippest",
props: {
sourcecode: String,
}
}
The problem is that the display of the component does not change while the prop is changing (checked on Vue devtools).
It might be the fact that code tag contains several spans, but I'm not sure.
The actual text is not directly in code tag, but in span inside it
Here's the use of the snippet component:
<template>
<div>
<v-row class="my-5">
...
<code-snippest **:sourcecode="code"** />
</div>
</template>
<script>
import CodeSnippest from "./CodeSnippest.vue";
export default {
name: "PlayGround",
components: {
CodeSnippest,
},
data() {
return {
baseTag: "button",
baseClass: "btn",
additionalClass: "outline",
additionalColor: "red",
outline: false,
staticc: false,
text: "button",
colors: ["red", "sunset", "sea", "white", "whale"],
};
},
computed: {
code() {
return `
<${this.baseTag} class="${this.baseClass} ${
this.outline ? this.additionalClass : "bg"
}-${this.additionalColor} ${this.staticc ? "static" : ""}">${
this.text
}</${this.baseTag}>
`;
},
},
};
</script>
The data changes by buttons and checkboxes, the computed is 100% changing.
Any ideas?
Thank you!

Creating a dynamic Vue list that can be updated via custom props in HTML

New to VueJS. I am trying to build a custom ul component for a webpage that can be populated and updated via custom props (preferably string, but doesn't have to be), specifically in the HTML so that any other dev can simply use/update/add to the custom component with said prop, and it will add a new li through the addition of a second, third, fourth, etc. prop, appending the previous li. I am also struggling to see if more than one input type can be used on a custom prop. For a better explanation heres a coded example of what I currently have and what I would like to do:
Vue.component('resources', {
template: `
<!-- Resources Component -->
<div class="resources">
<div class="heading">
<p>Resources</p>
</div>
<ul class="resource-list">
<li v-for="item in items">
<a :src="item[source]">{{ item.message }}</a>
</li>
</ul>
</div>
`,
props: {
source: {
type: String,
default: "."
},
message: {
type: String
}
},
data () {
return {
items: [
{
message: {
type: String
},
source: {
type: String,
default: "."
}
}
]
}
}
});
And in my HTML the component looks like this:
<helpful-resources
message="test"
source="."
></helpful-resources>
This 1000% has a lot of issues, but ideally I would like to have something along the lines of this:
<helpful-resources
item: src="example url 1" message="test message 1"
item: src="example url 2" message="test message 2"
></helpful-resources>
With every addition of a new 'item' appending the previous list item with a new one with the ability to change the src and the message over and over again as needed for however many items are needed in the list.
Any help/clarification would be greatly appreciated. Thanks!
In the parent component:
<template>
<div class="resources">
<div class="heading">
<p>Resources</p>
</div>
<Helpful-resources :listItems="listItems"></Helpful-resources>
</div>
</template>
<script>
#import HelpfulResources from '#/path/to/HelpfulResources';
export default {
name: 'Resource',
components: {
HelpfulResources
},
data() {
return {
listItems: [
{src: 'link to item', message: 'special message'},
{src: 'link to item2', message: 'special message2'},
// More items ...
]
}
}
}
</script>
<style lang="scss">
/* styles */
</style>
Your component could be structured like this:
Helpful-resources.vue
<template>
<ul class="resource-list">
<li v-for="(item, index) in listItems" :key="'listItem-'+index">
<a :href="item.src">{{ item.message }}</a>
</li>
</ul>
</template>
<script>
export default {
name: 'helpful-resource',
props: [ 'listItems'],
data() {
return {
// More data ...
}
}
}
</script>
<style lang="scss">
/* styles */
</style>
Note this is styled in the vue-cli fashion, but you can modify it to fit your needs.
EDIT
To include it within an html file you would place your Vue components within the body, script tags just below the body tag.
<div id="app">
<resources :source="someData" :message="message" id="r"></resources>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.10/dist/vue.js"></script>
<script>
let resources = Vue.component('resources', {
template: `<div class="resources">
<div class="heading"><p>Resources</p></div>
<ul class="resource-list">
<li v-for="(item, index) in items" :key="index"><a :href="source">{{ item.message }}</a></li>
</ul>
</div>`,
props: {
number: Number,
source: {
type: String,
default: "."
},
message: {
type: String,
default: 'No message'
},
// Example of multiple data types
propB: [String, Number]
},
data() {
return {
items: [
{
message: this.message,
source: this.source
}
]
}
}
});
new Vue({
el: '#app',
components: {
resources
},
data: {
someData: 'path/to/source',
message: 'Special Message'
},
});
</script>
Here's a link to the fiddle anyways...Fiddle
As far as updating the list goes, you could use an API call to get data asynchronously or allow users to add info via button or input and use a method. Or if you are talking strictly hardcoding extra values, other developers would add to your file...
Hopefully this helps. If not, please clarify.

Dynamically Generating Bind Variable Names

I have a data grid, in which I use dom-repeat to generate the columns.
<vaadin-grid-filter value=[[filterInput]] />
<input value={{filterInput::input}} />
</vaadin-grid-filter>
I bind the value used to filter a column with the value input into an input element.
My problem is each column binds to the same filterInput variable.
Is there any way I can bind using a variable for each specific column?
Could I somehow generate the binding variable for each column, e.g. filterInput[0], filterInput[1] etc. by using the index variable that comes with dom-repeat?
I make it working with an element.
HTML template
<template is="dom-repeat" items="{{technology}}">
<input type="text" value="{{item.label::input}}">[[item.label]]<br/>
</template>
Polymer Element
technology : {
type: Array,
value: [
{id:"php", label:"PHP", selected:false},
{id:"js", label:"Javascript", selected:false},
{id:"html", label:"HTML", selected:false},
{id:"css", label:"CSS", selected:false},
]
}
Full Polymer element
<dom-module id="input-array-element">
<template>
<h3>Inputs Array</h3>
<template is="dom-repeat" items="{{technology}}">
<input type="text" value="{{item.label::input}}">[[item.label]]<br/>
</template><br>
</template>
<script>
class InputArrayElement extends Polymer.Element {
static get is() { return 'input-array-element'; }
static get properties() {
return {
technology : {
type: Array,
value: [
{id:"php", label:"PHP", selected:false},
{id:"js", label:"Javascript", selected:false},
{id:"html", label:"HTML", selected:false},
{id:"css", label:"CSS", selected:false},
],
notify: true
}
}
}
ready() {
super.ready();
this.addEventListener("technology-changed", function(e){
console.log(e);
});
}
}
window.customElements.define(InputArrayElement.is, InputArrayElement);
</script>
</dom-module>

How to control ng-repeat divs from ng-repeat inputs

So, just getting started in Angular and it's pretty tricky, coming from a pretty simple JS and jQuery background. Here's what I'm trying to do. I have a "tag template" that has a couple categories and then some sub-tags contained within. I have defined these as an object, with the idea that the object/file can be called via file request and manipulated, etc.
I have loaded labels and tag category inputs dynamically by using a factory service and a controller with ng-repeat. Likewise, I have deposited the subtags into another div on page2 (using jQuery mobile page swiping). I'd like to use the checkbox state of the category tags to show/hide the sub-tags on page2.
I have tried dozens of things and searched all over stackexchange, the net, etc, but is simple and straightforward and similar enough for me to get it working. If someone can point me in the right direction, that would be great. Keep in mind that my next step is to add a button on page 1 to add a new category, and buttons on page 2 to add sub-tags to the sub-tag categories.
Finally, I have one more weird thing to report. If I only have two pages in my DOM, I have some weird behavior when loading the page. If I load from page 1, the tag checkboxes do not function, and I see a slight fattening of the border of the labels. If I swipe left to page 2 and reload from this page, the borders of the labels are thin and the checkboxes function. Cannot track down why this would be happening. My hacky workaround is to add an empty page zero and then changepage immediately to page one, but this is far from ideal. Any thoughts on that would be appreciated as well.
Here it is:
HTML
<!-- Angular version -->
<button class="ui-btn" onclick="selectTemplate();">My Template</button>
<form>
<div data-role="controlgroup">
<fieldset data-role="controlgroup">
<div ng-controller="templateCtrl">
<label
class="ui-checkbox"
ng-style="{backgroundColor: '{{tagCat.color | bgColor}}'}"
ng-repeat="tagCat in template"><input type="checkbox"
class="ui-checkbox"
id="{{tagCat.name}}"
ng-model="clicked"
ng-click="click();"
/>{{tagCat.name}}</label>
<div ng-repeat="tagCat in template">{{cb}} {{tagCat.name}} hallo</div>
</div>
</fieldset>
</div>
<div style="display:none" class="flashNotification"></div>
</form>
</div>
<div data-role="page" id="two">
<button class="ui-btn" onclick="selectTemplate();">My Template</button>
<form>
<div data-role="controlgroup">
<div ng-controller="templateCtrl">
<div ng-repeat="tagCat in template" ng-show="clicked" class="{{tagCat.name}}">{{tagCat.name}}
<fieldset data-role="controlgroup">
<label class="ui-checkbox"
ng-repeat="item in tagCat.items"
ng-style="{backgroundColor: '{{tagCat.color | bgColor}}'}"
for="item.name">{{tagCat.color | bgColor}}
<input class="ui-checkbox"
name="{{item.name}}"
id='{{item.name}}'
type="checkbox" />{{item.name}}</label>
</fieldset>
</div>
</div>
</div>
<div style="display:none" class="flashNotification"></div>
</form>
</div>
</div>
JS for jQuery Mobile
$(document).ready(function() {
// addTemplateItems(tagTemplate); // not necessary with Angular
// $.mobile.changePage('#two', { transition: 'none' }); // required or checkboxes don't work on load
$.mobile.changePage('#one', { transition: 'none' });
// // $("[data-role=controlgroup]").controlgroup("refresh");
// set up page nav
$(document).delegate('.ui-page', "swipeleft", function(){
var $nextPage = $(this).next('[data-role="page"]');
var $prevPage = $(this).prev('[data-role="page"]');
console.log("binding to swipe-left on "+$(this).attr('id') );
// swipe using id of next page if exists
if ($nextPage.length > 0) {
$.mobile.changePage($nextPage, { transition: 'slide' });
} else {
var message = 'tagged!';
// save tags here
flashNotify(message);
console.log('fire event!');
$('#flashNotification').promise().done(function () {
$('#group1').hide();
$('#group2').hide();
$('.ui-btn').hide();
// addTemplateItems(tagTemplate);
$.mobile.changePage($prevPage, { transition: 'none' });
captureImage();
});
}
}).delegate('.ui-page', "swiperight", function(){
var $prevPage = $(this).prev('[data-role="page"]');
console.log("binding to swipe-right on "+$(this).attr('id') );
// swipe using id of next page if exists
if ($prevPage .length > 0) {
$.mobile.changePage($prevPage, { transition: 'slide', reverse : true });
} else {
alert('no backy backy!');
}
});
// $("input[type='checkbox']").checkboxradio().checkboxradio("refresh");
});
JS for Angular App
var app = angular.module('STL', []);
app.factory('TagTemplate', [function () {
var TagTemplate = {};
var tagTemplate = {
family: {
name: "family",
description: "These are your family members.",
color: "red",
items: [
{
name: "Joe"
},
{
name: "Mary"
},
{
name: "Jim"
}
]
},
design: {
name: "design",
description: "Different types of design notes.",
color: "blue",
items: [
{
name: "inspiring"
},
{
name: "fail"
},
{
name: "wayfinding"
},
{
name: "graphics"
}
]
},
work: {
name: "work",
description: "Stuff for work.",
color: "green",
items: [
{
name: "whiteboard"
},
{
name: "meeting"
},
{
name: "event"
}
]
}
};
TagTemplate = tagTemplate;
return TagTemplate;
}])
// Controller that passes the app factory
function templateCtrl($scope, TagTemplate) {
$scope.template = TagTemplate;
$scope.click = function(model) {
console.log(this.checked, this.tagCat.name);
}
}
app.filter('bgColor', function () {
return function (color) {
// console.log(color, $.Color(color).lightness(.05).toHexString(.05));
// var rgba = $.Color(color).alpha(.05);
return $.Color(color).lightness(.97).toHexString();
}
})
For the main part, success!
I found a jsfiddle that gave me a good base for experimenting. After some playing, I realized that I just have to create a show property within each of the categories in my data service model, and then assign the ng-model to that property to control it.
I had to do it slightly differently in my own code, but the understanding gained from the following jsfiddle led me to the answer:
http://jsfiddle.net/Y43yP/
HTML
<div ng-app ng-controller="Ctrl">
<div class="control-group" ng-repeat="field in customFields">
<label class="control-label">{{field}}</label>
<div class="controls">
<input type="text" ng-model="person.customfields[field]" />
<label><input type="checkbox" ng-model="person.show[field]" /></label>
</div>
</div>
<button ng-click="collectData()">Collect</button><button ng-click="addField()">Add Field</button><br/><br/>
<em>Booleans</em>
<div ng-repeat="field in customFields">
<p>{{field}}: {{person.show[field]}}</p>
</div>
<em>Show/Hide</em>
<div ng-repeat="field in customFields">
<p ng-show="person.show[field]">{{field}}: {{person.customfields[field]}}</p>
</div>
</div>
JS
function Ctrl($scope) {
$scope.customFields = ["Age", "Weight", "Height"];
$scope.person = {
customfields: {
"Age": 0,
"Weight": 0,
"Height": 0
},
show: {
"Age": false,
"Weight": false,
"Height": false
}
};
$scope.collectData = function () {
console.log($scope.person.customfields, $scope.person.show);
}
$scope.addField = function () {
var newField = prompt('Name your field');
$scope.customFields.push(newField);
}
}
Still having the checkbox issue but I'll open a separate issue for that if I can't figure it out.
Thanks.