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

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.

Related

How to map a json list only after an onclick event in react?

Is there a way to use map() in order to feel objects into a datalist element, only after user clicks on that input?
for instance, I want the list of languages below to start filling data only if the user clicks on its input:
import React, { Component } from 'react';
import languages from './languages.json';
const langLi = languages.languages.map(languages => // i want this to happen only after clicking the input
<option>
{languages.lang}
</option>
)
class Form extends Component {
render () {
return (
<form>
<input type='text' list='langData'/>
<datalist id='langData'>{langLi}</datalist> //
</form>
)
}
}
When I inserted an onClick trigger to the input and wrote a function that fills the datalist's innerHTML, nothing happened. Is there a way to solve this?
Thanks!
Example of languages.json:
{
"languages":[
{"lang": "Chinese",
"country": "China",
"rank": 1},
{"lang": "Spanish",
"country": "Spain",
"rank": 2},
{"lang": "English",
"country": "United Kingdom",
"rank": 3}
]
}
You need to manage state on your React Component and insert elements via call function when event of your input is calling.
import React, { Component } from 'react';
import languages from './languages.json';
class Form extends Component {
construct(props) {
super(props);
this.state = {
languages: []
}
}
addLanguagesHandler = () => {
const myLanguages = this.state.languages;
myLanguages.push(); // <= Push your languages here
// Map new languages to state
this.setState({
languages: myLanguages
})
}
render () {
return (
<form>
<input type='text' list='langData' onFocus={() => this.addLanguagesHandler()} />
<datalist id='langData'>
{this.state.languages.map((language, index) => (
{/* Your logic for UI */}
<option key={index}>{language}</option>
))}
</datalist>
</form>
)
}
}
Yes, of course you have, and more than one
But one important thing to note: you are inside react, therefore you need to use react and not manipulate Dom directly.
You can fill state. I. e. this. setState({languages: fill()}) inside onclick
You can use a reducer
You can run this. languages = fillMyList(); and then this.forceUpdate(). this will fill the list with languages and then will rerender react shadow Dom (which in turn will update the real dom

How can i access to 'download_url' in json using vuejs

i want to get 'tags' and 'download url' inside meta, i cannot access to 'download_url' in json how i can do it, as a backend i am using wagtail cms, and is it good to use vue js with wagtail cms (headless cms)
<template>
<div>
<div>
<b-card-group deck v-for="item in results" :key="item.id">
<b-card
>
<b-card-text>
<div v-for="block in item.body" :key="block.id">
<div v-if="block.type == 'heading'">
<h2>{{block.value}}</h2>
</div>
<div v-if="block.type == 'image'">
<img :src="'http://127.0.0.1:8000/api/v2/images/' + block.value">
</div>
<div v-if="block.type == 'paragraph'">
<h2 v-html="block.value">{{block.value}}</h2>
</div>
</div>
</b-card-text>
>
</b-card>
</b-card-group>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Home',
data () {
return {
results: null
}
},
mounted () {
axios.get('http://127.0.0.1:8000/api/v2/pages/?type=news.NewsPage&fields=intro,body,image_thumbnail')
.then((response) => (
this.results = response.data.items
))
}
}
</script>
here is json api. i accessed till id of image and do not know what to do next
{
"id": 3,
"meta": {
"type": "wagtailimages.Image",
"detail_url": "http://localhost/api/v2/images/3/",
"tags": [
"gadget",
"phone",
"samsung"
],
"download_url": "/media/original_images/affordable_new_9-7-inch_ipad_group_fan2_1_1.png"
},
"title": "affordable_new_9-7-inch_ipad_group_fan2 1 (1).png",
"width": 528,
"height": 357
}
Assuming that response.data.items is the json you showed above, you can extract just what you want from there. Right now, your component has the whole response.data.items in this.response. So if you want all of it there, keep that.
You can store the 'tags' and 'download url' to your component by adding two new pieces of data ie add them to your data:
data () {
return {
results: null,
tags: null,
downloadUrl: null
}
... and then set those in your response block from the request's response like this.
mounted () {
axios.get('http://127.0.0.1:8000/api/v2/pages/?type=news.NewsPage&fields=intro,body,image_thumbnail')
.then((response) => (
this.results = response.data.items
this.tags = response.data.items.meta.tags
this.downloadUrl = response.data.items.download_url
))
}
When dealing with nested response objects like this, it can help to make a local variable with the data and add it that way. Also, if you dont need the whole response, you can avoid storing it and just store the data from the response that you want to your component here. If you wanted to get something from your this.response, you're going to have to go deep into it. It would be cleaner to just pull out only what you need, and then use it in your code with just one {{myStuffIPulledOut}} vs {{response.thingIWantBefore.actualThing.}}

How to make filters in Vue.js based on element list?

Introdution
Hi, I'm working on private project "Avatar databse" in Vue.js framework. App shows them based on data() elements:
data() {
return {
avatars: [
{
name: "Butterfly Blue",
tags: [
"animal",
"butterfly",
"blue"
]
},
{
name: "Butterfly Green",
tags: [
"animal",
"butterfly",
"green"
]
},
{
name: "Deer Shining",
tags: [
"animal",
"deer"
]
},
What I want
I would like to make search engine based on tags. Most of help pages are about previous Vue versions or search is based on name - one element. I want to search in tag list not single name string.
Without search engine, every avatar renders correctly
Current component code
template:
<div class="row">
<div v-for="image in avatars" :key="filteredData" class="col-6 col-sm-4 col-md-3 col-lg-2 my-2">
<img v-bind:src="imgSource(image.name)" v-bind:alt="image.name" class="img-fluid" :class="avatarClass" />
<a :href="imgSource(image.name)" :class="downloadClass"><span class="icon-download-alt"></span></a>
<p class="h5 text-center py-1">{{ image.name }}</p>
<p v-for="tag in image.tags" v-bind:key="tag" :class="tagClass">{{ tag }}</p>
</div>
</div>
computed()
avatarClass() {
return 'avatar';
},
tagClass() {
return 'tag';
},
downloadClass() {
return 'download';
},
filteredData() {
if (this.search == '') {
return this.avatars;
} else {
return this.avatars.filter(obj => {
return obj.name.toLowerCase().includes(this.search.toLowerCase());
});
};
},
Of course filterind related thigs doesn't work. And there's my question...
How to make working, tag list based, search engine?
(Based on my project.)
It's small changes to the search that has been done. I've made a codesandbox where it's working:
https://codesandbox.io/s/festive-napier-3jk52
filteredData() {
if (this.search == "") {
return this.avatars;
} else {
return this.avatars.filter(obj => {
return obj.tags.indexOf(this.search.toLowerCase()) !== -1;
});
}
}
It's pretty simple. There's a search data variable, where you can put in the tag you want to search for. Right now it only searched for the whole tag, and has to match a tag fully, but this can be changed if you want people to be able to search for "anim", and then the avatars with the "animal" tag should be shown.
You enter butterfly in your search field and only Butterfly Blue and Butterlfy Green should appear?
Instead of
return this.avatars.filter(obj => {
return obj.name.toLowerCase().includes(this.search.toLowerCase());
});
try this:
return this.avatars.filter(avatar => avatar.tags.includes(this.search.toLowerCase()));

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.