VUE-JS - CHECKBOX V-MODEL - json

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

Related

How to pass vue component props array of object?

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>

Why data get displayed on the html and instantly disappear? Angular

I receive an array of objects in which I have to create new properties to display in the html
public inicializeData() {
this.loaderService.eLoader.emit(true);
this.cartsSubscription = this.cartsService.getCarts().subscribe(carts => {
this.orders = carts;
this.orders.forEach(cart => {
cart.date = cart.functional_id.substring(0, 8);
cart.order_number = cart.functional_id.substring(8, 14);
});
this.load = true;
this.loaderService.eLoader.emit(false);
});
}
so that an object after the creation of the new properties
{
"functional_id": "201911291131250012400000SD4AYAA1",
"transactions": [
{
"quantity": 2,
"price": 140,
"item": {
"name": "Carton de 10 coffrets",
"description": "+ 2 recharges d'argile offertes",
"product": {
"name": "Coffret empreinte rouge"
}
}
},
{
"quantity": 1,
"price": 0,
"item": {
"name": "Petit modèle",
"description": "Par 25",
"product": {
"name": "Sacs blancs",
"description": "Pour les crémations Plurielles"
}
}
}
],
"date": "20191129",
"order_number": "113125"
},
In this function I extract from the property 'functional_id' a data formed by the first 8 digits, which correspond to the date of creation, and another formed by the following 6 digits, which corresponds to a registration number.
These are the data I keep in this function with the name of 'cart.date' and 'cart.order_number' respectively.
When I show them in the html they load immediately but, in a matter of a second, the two data I created disappear from the screen.
<div class='order-list'>
<span *ngIf="!orders.length">No orders available</span>
<div class="fade-in" *ngFor="let order of orders; let i = index;">
<div class="row ciev-row header-row d-none d-lg-flex" [ngClass]="{'last': i === orders.length - 1}" (click)="toggle(order)">
<div class="col-sm-2 my-auto">{{order.functional_id}}</div>
<div class="col-sm-2 my-auto">{{order.date | date}}</div>
<div class="col-sm-2 my-auto">{{order.order_number}}</div>
</div>
</div>
I don't understand why I can't find a solution.
Someone to give me an idea that I am doing wrong.
Recently I faced similar kind of issue.
My goal was to add the text to a list below a text html input box when user enters something into it and hits enter key.
import { Component, OnInit } from '#angular/core';
import { FormArray, FormControl, FormGroup } from '#angular/forms';
#Component({
selector: 'add-subject-form',
template: `
<form (submit)="doNotSubmitForm($event)">
<input
type="text" class="form-control"
(keyup.enter) = "addSubject(subject)" #subject>
<ul class="list-group">
<li
*ngFor="let item of items.controls"
class="list-group-item">{{item.value}}</li>
</ul>
</form>
`,
styleUrls: ['./add-subject-form.component.css']
})
export class AddSubjectFormComponent{
form = new FormGroup({
subjects: new FormArray([])
});
addSubject(pItem: HTMLInputElement) {
this.items.push(new FormControl(pItem.value));
pItem.value = '';
}
get items() {
return this.form.controls['subjects'] as FormArray;
}
// By default the form gets submitted on keyUp.enter event.
// doNotSubmitForm method prevents that default behaviour
doNotSubmitForm(event: any) {
event.preventDefault();
}
}
I could achieve the functionality using above template and necessary code in corresponding ts component class. But the problem was the text box was becoming empty and the list below it was vanishing as the html form was getting submitted by default on keyup.enter event.
Hence I had to call following method on submit event of the form.
doNotSubmitForm(event: any) {
event.preventDefault();
}
Hope this information enriches the context.
I was stuck with the fact that the data disappeared on the screen thinking that it was a problem of html or css and I didn't see why. But in reality it was a problem of the subscription that depended on a service called in other components and by the flow of the application I entered twice and it overwrote me the data, showing the originals.
Thank you all for your time and help.

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.

How to implement nested data form in angular2

Here is Json schema :
{
"_id" : ObjectId("59031d77fd5e1c0b3c005d15"),
"resume_data" : {
"work_experience" : [
{
"company" : "example",
"website" : "example.com",
"position" : "Internship",
"highlights" : "Learn To Create API In Laravel Framework. and also Learn Angular 2 for Front end Development.",
"project_experience" : [
{
"projectName" : "Fb Project",
"teamMember" : "5",
"technology" : "PHP,Laravel-5,Angular-2,MongoDb",
"projectPosition" : "Back-end Developer"
}
]
}
]
}
}
Here is image:
I have reference of this answer but i don't know about nested form data. can anyone explain how to implement it.
Here is your code, which sets the data you are receiving from backend, here I have stored it in a variable data.
Please notice, this is a shortened version of your form, but the basics are there, you only need to add the few missing properties in corresponding form arrays.
The build of the empty form looks is just a FormArray named work_experience matching your json structure:
this.myForm = this.fb.group({
work_experience: this.fb.array([])
})
We add the fields when you are receiving the data, call a function called setWorkExperience in the callback when receiving data:
setWorkExperience(){
// get the formarray
let control = <FormArray>this.myForm.controls.work_experience;
// iterate the array 'work_experience' from your JSON and push new formgroup with properties and the inner form array
this.data.work_experience.forEach(x => {
// add the rest of your properties also below
control.push(this.fb.group({company: x.company, project_experience: this.setFormArray(x)}))
})
}
setFormArray is called from the previous function, where we patch the data with from project_experience to the inner form array:
setFormArray(x) {
// create local array which is returned with all the values from the 'project_experience' from your JSON
let arr = new FormArray([])
x.project_experience.map(y => {
// add the rest of your properties below
arr.push(this.fb.group({projectName: y.projectName}))
})
return arr;
}
The template would then look like this:
<form [formGroup]="myForm">
<!-- Outmost array iterated -->
<div formArrayName="work_experience">
<div *ngFor="let a of myForm.get('work_experience').controls; let i=index">
<h3>COMPANY {{i+1}}: </h3>
<div formGroupName="{{i}}">
<label>Company Name: </label>
<input formControlName="company" /><span><button (click)="deleteCompany(i)">Delete Company</button></span><br><br>
<!-- inner formarray iterated -->
<div formArrayName="project_experience">
<div *ngFor="let b of myForm.controls.work_experience.controls[i].controls.project_experience.controls; let j=index">
<h4>PROJECT {{j+1}}</h4>
<div formGroupName="{{j}}">
<label>Project Name:</label>
<input formControlName="projectName" /><span><button (click)="deleteProject(a.controls.project_experience, j)">Delete Project</button></span>
</div>
</div>
<button (click)="addNewProject(a.controls.project_experience)">Add new Project</button>
</div>
</div>
</div>
</div>
</form>
In the template you can see the buttons for add and delete of projects and companies. Adding and deleting companies are straightforward, where initCompany() returns a formGroup:
deleteCompany(index) {
let control = <FormArray>this.myForm.controls.work_experience;
control.removeAt(index)
}
addNewCompany() {
let control = <FormArray>this.myForm.controls.work_experience;
control.push(this.initCompany())
}
In the add project we pass as parameter from the template the current formArray control, to which we just push a new FormGroup:
addNewProject(control) {
control.push(this.initProject())
}
In the delete function we pass the current formarray as well as the index of the project we want to delete:
deleteProject(control, index) {
control.removeAt(index)
}
That should cover pretty much everything.
Plunker
Please Check it Out This
Plunker Here
Json Store Like This
{
"name": "",
"work_experience": [
{
"name": "asdasd",
"project_experience": [
{
"Project_Name": "asdasdasd"
},
{
"Project_Name": "asdasdasd"
}
]
}
]
}

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.