ReBuild/Re-render Angular2 component when property is changed - properties

How to Implment this?
My SubComponent
import {Component,Input,ngOnInit} from 'angular2/core';
#Component({
selector: 'my-component',
template: `
<div>In child component - myAttr = {{ myAttr1 }}</div>
`
})
export class MyComponent {
#Input() myAttr: number;
myAttr1:number;
ngOnInit()
{
this.myAttr1=this.myAttr*10;
}
}
Main Component
import {Component} from 'angular2/core';
import {MyComponent} from './sub.component';
#Component({
selector: 'my-app',
template: `
<my-component
[(myAttr)]="myAttr"
></my-component>
<button (click)="onClick()">Click</button>
`,
directives: [MyComponent]
})
export class AppComponent {
myAttr: number = 1;
onClick() {
console.log('Click in the parent component');
this.myAttr += 1;
}
}
I need to update the value in each click. There should be a direct approach , else Angular2 team should think about this

You should use ngOnChanges to detect when myAttr is updated in your sub component:
#Component({
selector: 'my-component',
template: `
<div>In child component - myAttr = {{ myAttr1 }}</div>
`
})
export class MyComponent {
#Input() myAttr: number;
myAttr1:number;
ngOnInit() {
this.myAttr1=this.myAttr*10;
}
ngOnChanges() { // <------
this.myAttr1=this.myAttr*10;
}
}
This allows to detect when the myAttr input property is updated and update accordingly the myAttr1 one.
See this plunkr: https://plnkr.co/edit/2SOdq7w3s8iDxBKbiLpU?p=preview.

Related

Import component and its properties/methods inside other component

if i have component LogoutButton.vue
export default {
data()
{
return {
}
},
methods:
{
Logout()
{
console.log("something")
}
}
}
</script>
<template>
<button #click="Logout">Logout</button>
</template>
How can i use the LogoutButton component inside other component?
I mean how can i import the component and its click methods inside other component?
<script>
import LogoutButton from './LogoutButton.vue'
export default {
components: {
LogoutButton
},
data()
{
return {
}
},
methods:
{
// Your different methods
}
}
</script>
<template>
<div>
<!-- The template from LogoutButton component will display here -->
<LogoutButton />
</div>
</template>

vue graphql composition api :data binding

//This is my HomeView
<template>
<div class="home">
<div class="error" v-if="error">Error: {{error.message}}</div>
<div v-else> <BlogList :allBlogs="allBlogs" /> </div>
</div>
</template>
<script>
import { useQuery, useResult } from '#vue/apollo-composable'
import gql from 'graphql-tag'
import BlogList from '../components/BlogList.vue'
// # is an alias to /src
const ALL_BLOGS = gql`
query{
allBlogs{
id
title
author
body
yearPublished
}
}`
export default {
name: 'HomeView',
components: { BlogList },
setup() {
const {result, error } = useQuery(ALL_BLOGS)
// We use use result for nested queries
const allBlogs = useResult(result, null, data => data.allBlogs)
return { allBlogs, error}
}
}
</script>
<style></style>
//This is my BLogList
<template>
<div v-for="blog in allBlogs" :key="blog.id">
<SingleBlog :blog='blog' />
</div>
</template>
<script>
import SingleBlog from '../components/SingleBlog.vue'
export default {
props: ['allBlogs'],
components: { SingleBlog },
}
</script>
<style></style>
//This is my SingleBlog
<template>
<router-link :to="{name: 'Details', params: {id: blog.id}}"><h1>{{blog.title}}</h1></router-link>
<p>{{snippet}}</p>
</template>
<script>
import { computed } from '#vue/runtime-core'
export default {
props: [ 'blog' ],
setup(props) {
const snippet = computed(() => {
return props.blog.body.substring(0,100) + '....'
})
return { snippet }
}
}
</script>
<style></style>
//This is my Details view
<template>
{{blog.title}}
</template>
<script>
import { useQuery, useResult } from '#vue/apollo-composable'
import gql from 'graphql-tag'
export default {
props: ['id'],
setup(props) {
const {result, error} = useQuery(gql`
query allBlogs($id: ID!){
allBlogs(id: $id){
id
title
author
body
yearPublished
}
}
`, props)
const blog = useResult(result)
return {blog, error }
}
}
</script>
<style></style>
In the above code everything works fine, until i get to Details view. The fetching graphql api (django backend) for list of blog I've created works fine. However, trying to see the detail of the blog which has been router-linked to Singleblog is not working. I tried to use the example provided on vue apollo site.
Does anyone have any idea what might be the problem is with my code at Details.vue?

Vue 3 - template ref with computed?

How may I focus on this simple input example?
Should I create one more variable const nameRef = ref(null) or there is more beauty way to resolve this?
<template>
<input ref="name" :value="name" />
</template>
<script>
import {ref, computed} from 'vue';
export default {
props: ['name'],
setup(props) {
const name = computed(() => someTextPrepare(props.name));
// how can I do name.value.focus() for example?
return { name }
}
}
</script>
Try to wrap the name value and ref in reactive property :
<template>
<input :ref="theName.ref" :value="theName.value" />
</template>
<script>
import {ref, computed,reactive} from 'vue';
export default {
props: ['name'],
setup(props) {
const theName=reactive({
value:computed(() => someTextPrepare(props.name)),
ref: ref(null)
})
return { theName }
}
}
</script>

Angular undefined value of #input variable

I'm new to Angular and I have some issues , hope you'll help me.
so I'm trying to share a value of a variable from a ProjectComponent to an AcceuilComponent , the value of this variable is displaying correctly into my acceuil.component.html but when I try to use it into my acceuil.component.ts it's undefined !
project.component.html (the parent component)
<app-header-in></app-header-in>
<ng-sidebar-container>
<ng-sidebar [opened]="opened">
<p> Sidebar </p>
<button (click)="Sidebar()">
Close Sidebar
</button>
<ul class="menu">
<li class="hh"
*ngFor="let project of projects"
[class.selected]="project === selectedProject"
(click)="onSelect(project)">
{{project.nomprojet}}</li>
</ul>
</ng-sidebar>
<div ng-sidebar-content >
<br><br><br><br>
<button (click)="Sidebar()">
Open Sidebar
</button>
<app-acceuil [message]="idProject"></app-acceuil>
</div>
</ng-sidebar-container>
project.component.ts
import { Component, OnInit } from '#angular/core';
import { ApiService } from '../api.service';
import {ProjectService} from '../project.service';
import {PartService} from '../part.service';
#Component({
selector: 'app-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.css']
})
export class ProjectComponent implements OnInit {
opened=true;
projects:any;
idProject;
selectedProject;
constructor(private projectService:ProjectService) { }
ngOnInit(): void {
this.projectService.getProjects().subscribe((result)=>{console.log("result",result)
this.projects=result})
}
Sidebar(){
this.opened=!this.opened;
}
onSelect(pro): void {
this.idProject = pro.id;
}
}
acceuil.component.html (my child component)
<p>{{message}}</p>
<ul >
<li class="hh"
*ngFor="let part of parts">
{{part.nomparti}}
</li>
</ul>
acceuil.component.ts
import { Component, OnInit,Input } from '#angular/core';
import { ApiService } from '../api.service';
import {PartService} from '../part.service';
#Component({
selector: 'app-acceuil',
templateUrl: './acceuil.component.html',
styleUrls: ['./acceuil.component.css']
})
export class AcceuilComponent implements OnInit {
#Input() message;
parts:any;
constructor(private partService:PartService) {
}
ngOnInit(): void{
console.log("id",this.message);
this.partService.getPartsFromIdProject(this.message).subscribe((result)=>{console.log("result",result)
this.parts=result})
}
ngOnChanges() {
if(this.message) {
console.log(this.message)
}
}
}
I'm using the message to call a service and displaying data .
in the acceuil.component.html <p>{{message}}</p> is displaying correctly but console.log("id",this.message); in acceuil.component.ts displays undefined
As message is an input property, you need to get its value in ngOnchanges life cycle.
First time, when it is in ngOnChanges, input value will be undefined. So for the safe side, better to add a check for not undefiled condition like below
ngOnChanges(changes: SimpleChanges) {
if (changes.message) {
// Should be defined now
console.log(this.message);
}
}

How to access an Vue component within another component?

I'm using the single file components, but I can't access a component via another component, follow what I've tried...
<template>
<div id="containerPrincipal" #click.stop="teste">
...
<template>
<script>
/*Other component*/
import flex_div from './elementos/Div.vue'
export default {
name: 'containerPrincipal',
methods : {
teste () {
componente = new flex_div().$mount();
console.log(componente);
}
},
components: {
flex_div
}
}
</script>
Error
_Div2.default is not a constructor
How can I fix this?
To resolve I had to instantiate the Vue again and reference the component...
<template>
<div id="containerPrincipal" #click.stop="teste">
...
<template>
<script>
/*Other component*/
import Vue from 'vue'
import flex_div from './elementos/Div.vue'
let flexdiv = Vue.component('divFlex', flex_div);
export default {
name: 'containerPrincipal',
methods : {
teste () {
let componente = new flexdiv().$mount();
console.log(componente);
}
},
components: {
flexdiv
}
}
</script>
I might be wrong but isn't this what you want to do?
<template><
<div id="containerPrincipal" #click.stop="teste">
<flex-div ref="flex_div"></flex-div>
</div>
<template>
<script>
/*Other component*/
import Vue from 'vue'
import flexdiv from './elementos/Div.vue'
export default {
name: 'containerPrincipal',
methods : {
teste () {
let componente = this.$refs.flex_div
console.log(componente);
}
},
components: {
flexdiv
}
}
</script>