recently I've been using vue in frontend and vue-router with it to shape a SPA.
My problem is that I am not able to access a component defined in main Vue instance:
import ElementComponent from './Element';
const app = new Vue({
el: '#app',
router,
components: { Element: ElementComponent }
});
Whenever I do <element></element> within the #app scope the component gets rendered but I can not use the element inside a route component.
My routes are defined like this:
var routes = [
{ path: '/section/part', component: require('../views/Part') }];
And then provided to router instance:
new VueRouter({routes});
Breakpoint whenever I try to call <element></element> inside Part component template I get this in vuedevtools: [Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
(found in at C:\Users\Doe\project\js\views\Part.vue)
You need to import the component into the views/Part component. So do the same thing that you did in the main Vue instance, but only in the part component.
I believe if you want to make components global you need to do use
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
reference https://v2.vuejs.org/v2/guide/components.html#Registration
Related
I am working on nuxt 3 and I need re render component after API response.
<template>
<AssetsTab
:form-data="formData.assets"
:loader="loader"
#on-submit="submitForm"
/>
</template>
<script setup>
onMounted( async () => {
await getDetails(); //API call
});
</script>
Here once the API call getDetails() successed. I need to rerender AssetsTab component again.
Use a reactive variable like const isApiRespond = ref(false) and make the variable true in the getDetails function when you get the successful API response. Then in the template use v-if like below,
<AssetsTab
v-if=isApiRespond
:form-data="formData.assets"
:loader="loader"
#on-submit="submitForm"
/>
Now if you again want to Re-Render your component then use a key prop in your component. Whenever your props value update, the component will auto-update.
<AssetsTab
v-if=isApiRespond
:key="rerendervalue"
:form-data="formData.assets"
:loader="loader"
#on-submit="submitForm"
/>
In above code whenever your key value update the whole component will auto update.
Here is a VuePlaygroud Link check it's console you will understand.
Let's say I have a simple Angular Component:
#Component({
selector: 'app-email-content',
template: '<h1>Welcome {{username}}!</h1>'
})
export class WelcomeEmailComponent {
#Input() username: string
}
My goal is to take this Angular component and render it to plain HTML with Node.Js, to send customized EMails.
I know that Server-side rendering is definitely possible with Angular Universal. But I am not sure how to explicitly render one specific component.
The approach is to send an Angular component-based dynamically generated templates to users' email from the Angular SSR project.
Find the example repository at the bottom of this answer.
The steps you need to follow;
Design your templates in an individual routing path that is dedicated to showing only the email templates not your navigation bars, global CSS, etc.
Example:
welcome-email-component.component.ts
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-welcome-email-component',
templateUrl: './welcome-email-component.component.html',
styleUrls: ['./welcome-email-component.component.css']
})
export class WelcomeEmailComponentComponent implements OnInit {
username: any;
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.route.params.subscribe(params => {
this.username = params.username;
});
}
}
welcome-email-component.component.html
<style>
.title-p {
color: #00025a;
font-size: 20px;
font-weight: bold;
}
</style>
<p class="title-p">Welcome {{username}}</p>
You need to specify a route for this component as below, so when the user navigates to the welcome-email/username route it should show only the email template generated component.
{ path: 'welcome-email/:username', component: WelcomeEmailComponentComponent }
Implement Angular SSR to your project from the great Angular SSR guidelines, Server-side rendering (SSR) with Angular Universal.
It's just two lines of code.
ng add #nguniversal/express-engine
npm run dev:ssr
Finally create a server-side API to generate the template from your Angular component and send emails or provide the HTML code of the single component, add the API function in your server.ts as below.
server.ts
server.get('/api/send-email/:username', (req, res) => {
// Below is the URL route for the Angular welcome mail component
request(`http://127.0.0.1:4200/welcome-email/${req.params.username}`, (error, response, body) => {
// TODO : Send email to the user from WelcomeEmailComponentComponent.ts component as `body`
// use the body to send email
res.send('Email sent');
});
});
Example code: https://github.com/aslamanver/angular-send-component-email
The demonstration of a dynamically generated component on this repository;
Finally when you access /api/send-email/:username, this will generate the welcome mail component and give the HTML body of that, thereafter you can proceed with your email sending function.
I clap #Googlian's answer. But, angular produces too much unfamiliar HTML5, CSS3 and angular specific bundled features, so after that you have to remove those one by one specifically if you want a real valid email content, otherwise your email most probably will be considered as spam bu mailclients.
I sugges that you mah have a component with xHTML standarts with no-CSS3, no-experimental HTML5 features, and build an email templete with this and ElementRef, then parse required fields manually.
Send the string to serverside, nodejs, then send it as email. You can use nodemailer
I was migrating a 7.1 DXP portal to 7.2 DXP but I can not bring my custom form field to work.
I used the dynamic-data-mapping-form-field-type module as a blueprint. My new field is available inside of the form builder - but when using it, nothing gets rendered. I don't have an errors on build, deploy or in JS console. Unfortunately, there is no blade example for 7.2 yet so that I could not start with a simple example.
My question is: how to hook in the field Soy template to render?
It is being implemented in https://issues.liferay.com/browse/LPS-98417 and it is true there is no blade example.
Meanwhile you can download following example code:
https://github.com/natocesarrego/slider
In case anyone is here for Liferay 7.3. Liferay 7.3 moved from soy templates to pure react components. You could use Liferay's module as a blueprint again.
import { FieldBase } from 'dynamic-data-mapping-form-fieldtype/FieldBase/ReactFieldBase.es'
import React, { useState, useEffect, useRef } from 'react';
const Text = ({ readOnly,
id,
name,
onBlur,
onChange,
onFocus,
placeholder,
value: initialValue }) => {
const [value, setValue] = useState(initialValue);
return (
<>
<input type="text" />
</>
);
};
const Main = (props) => {
return (
<FieldBase {...props}>
<Text {...props} />
</FieldBase>
);
}
export default Main;
In this case we are importing FieldBase component that is the Liferay field wrapper that will take care of adding any default Liferay behavior (validation, names, placeholder, tooltip etc...). We did the same when we used Soy templates.
You can create the module from form-field blade template. Then remove the soy template files along with the following line in package.json
"build-soy": "metalsoy --externalMsgFormat \"Liferay.Language.get(‘\\$2’)\" --soyDeps \"./node_modules/clay-*/src/**/*.soy\" \"./node_modules/com.liferay.dynamic.data.mapping.form.field.type/META-INF/resources/+(FieldBase|components)/**/*.soy\""
since we don't have any soy template to generate JS from.
What you will end up is just an es.js file.
Edit:
If you are using blade to generate the template, you can use this option to generate a react based component:
--js-framework react
I am creating a web application which uses SVG.
I have created components consist of SVG element, and they are put into a root svg element.
They have attribute selector, because SVG/XML document tree is strict so I cannot use element selector.
And they have a template starts with svg:g tag:
#Component({
selector:'[foo]',
template: '<svg:g>...</svg:g>',
})
In the application, I want to create a component when a user press a button,
and simultaneously start dragging it.
I thought it can be achieved by creating a component dynamically using ComponentResolver:
#ViewChild('dynamicContentPlaceHolder', {read: ViewContainerRef})
protected dynamicComponentTarget: ViewContainerRef
private componentResolver: ComponentResolver
onMouseDown() {
this.componentResolver
.resolveComponent(FooComponent)
.then((factory) => {
const dynamicComponent = this.dynamicComponentTarget.createComponent(factory, 0)
const component: FooComponent = dynamicComponent.instance
const element = dynamicComponent.location.nativeElement
// add event listener to start dragging `element`.
})
}
Component is created when onMouseDown() called, but its DOM element is div, so it is illegal element in svg document and cannot be displayed.
I have tried with selector='svg:g[foo]', then g element is created, but its namespace is not for SVG (http://www.w3.org/2000/svg), but normal HTML namespace (http://www.w3.org/1999/xhtml) and its class is HTMLUnknownElement > g.
I also tried with selector='svg:svg[foo]', then svg:svg element is created and it is displayed. But svg:svg cannot move with transform attribute so this doesn't work well for my application.
How can I dynamically create svg:g element for attribute selector component?
I am using Angular2: 2.0.0-rc4.
You're right about the namespacing issues keeping the g element from rendering as svg. Unfortunately, attaching the node as an svg element is the only way to feasibly get the component to namespace properly.
However, this doesn't mean this won't work. If you add the drag functionality as a directive on the g element in the template, it will be compiled with your component, and you can offset your logic into that directive. The top level svg will be namespaced correctly, and the template will inherit this accordingly.
import {Component, Input} from '#angular/core';
#Component({
selector: 'svg:svg[customName]', // prevent this from hijacking other svg
template: '<svg:g dragDirective>...</svg:g>', // note the directive added here
style: []
})
export class GComponent {
constructor() { }
}
This may not be ideal, but until https://github.com/angular/angular/issues/10404 is resolved, there's not much of an alternative.
I am not sure that my solution is right but it works for me (even with ivy):
#Component({
...
})
class ParentComponent {
constructor(
private injector: Injector,
private appRef: ApplicationRef,
private componentFactoryResolver: ComponentFactoryResolver,
) {}
createDynamicComponent() {
let node = document.createElementNS("http://www.w3.org/2000/svg", "svg");
let factory = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
let componentRef = factory.create(this.injector, [], node);
this.appRef.attachView(componentRef.hostView);
}
}
After that you must manually append node into DOM.
Instead of trying to create your component to the view with the Component Resolver I will do this instead.
Create a object with properties which match the attributes you want to pass to your SVG Component.
Append this object to an array (ex.svgItems).
Add *ngFor="svgItem in svgItems" to the SVG component you want to create dynamically.
Hope it's clear and solve your problem.
i have a route which renders an overlay modal.
i want it to animate-in if i navigate from the UI,
and be loaded as static when navigating from the address bar or after a refresh.
i use nodejs and react + react-router.
i thought about using my universal redux setup to match a state prop for this issue, but maybe there's a much more elegant solution
thanks!
This can be achieved by testing the prevPath property on the props.location object
const [isFirstLoad,setIsFirstLoad] = useState(false)
const {location} = props
useEffect(()=> {
props.prevPath ? setIsFirstLoad(true) : setIsFirstLoad(false)
}, [location])
return <Modal animate={!isFirstLoad}/>
Each render UseEffect will test the props.location (similar to componentWillReceiveProps()) to check if the previous path is different. On load the prevPath property won't exist, so it will be false.