Vue 3 pass tamplate part to another component - vue.js

I have a Vue 3 application with router. (Using Bootstrap)
I have deep component in header, and main container (page in RouterView).
Question: I want to show few icons in header, but use it from page component.
What I must to use to do that?
I try to send template, dynamic import and etc, but as i understand it`s wrong ways.
I have same struct:
App
Header
Title
Icons
LeftMenu
MainContant
PageTitle
PageContant <- RouterView
Footer
So I have special template to Header Icons for each page. And I want to work with icons from page component. For example make submit icon.

I'm not completely sure if I understand the question correctly. But from what I get you want to have a slot in your Header component - docs.
So you can use it in MainContainer as follows:
<div>
<Header>
<Icon />
</Header>
</div>
In this case you'll have access to the Icon components in your MainContainer template.

Related

Control Vue component from nested layout using Inertia JS

I'm using Inertia JS using Vue and nested Layouts.
My main layout looks something like this:
<template>
<div>
<app-bar title="App title" type="back|dismiss|sidebar">
<!-- Slot for icons in the top right corner -->
</app-bar>
<slot />
</div>
</template>
So, an AppBar component accepting a title, a link with a back icon, dismiss icon or sidebar icon, and a slot (optionally) to provide icon links relevant to the current page.
<script>
import Layout from '#/Pages/Messenger/Layout';
export default {
metaInfo: { title: 'Report new problem' },
layout: [Layout],
...
</script>
This is a Page that is nested in the Layout.
So my question is: what is the best/preferred way to control the props and slot of the AppBar from nested Pages?
A bit like as you would do using Blade templates in Laraval or as Vue Meta does for the document page title as seen in the example above.
Maybe this is not even the best approach, in that case also let me know :)
If you are trying to pass information from your child component to your parent component such as a title, you can use $emit.
Here is a article describing how: https://hvekriya.medium.com/pass-data-from-child-to-parent-in-vue-js-b1ff917f70cc
And another SO question: https://stackoverflow.com/a/52479745/4517964
The fast way I found to pass data to persistent layouts is by:
in the child
use this:
layout: (h, page) => { return h(Layout, () => page) }
instead of:
layout: Layout,
and in the parent layout you can access your child with this.$slots.default()[0]

Is it possible to globally define links to use a specific component?

I'm currently trying to use Nav with react-router. The default behavior reloads the page, so I'm trying to use the Link component from react-router-dom.
It's quite difficult to preserve the default styling when overriding linkAs.
Is there any global way to override link navigation behavior?
Like defining a global link render function, which I can then set to render the Link component from react-router-dom?
Yes, it's possible!
2 things are required:
Make a wrapper component that translates the Nav API to react-router-dom links.
Specify the linkAs prop to the Nav component.
Wrapper component
This is a simple component that creates a react-router-dom link while using styles from Fabric:
import { Link } from "react-router-dom";
const LinkTo = props => {
return (
<Link to={props.href} className={props.className} style={props.style}>
{props.children}
</Link>
);
};
Specify component for use in Nav
<Nav groups={links} linkAs={LinkTo} />
Have also created a full working example at https://codesandbox.io/s/xenodochial-wozniak-y10tr?file=/src/index.tsx:605-644

How to submit a form from another component when the modal OK button is clicked (bootstrap vue)

In my Vue app, I have a component that handles a simple form named TodoForm.
Using bootstrap-vue, i would like to submit this form when the OK button of a bootstrap modal is pressed.
The code looks like this:
<b-modal id="todo-form-modal">
<todo-form />
</b-modal>
I don't want to put the modal component inside the TodoForm component since the TodoForm component only handles the form behavior, not the container where it is displayed.
I could also disable the OK button and put a button inside the form myself, but i'm sure there is a proper, a better way to submit this form (it is more like an exercise than a real project with an actual deadline).
I found the #ok event in the doc (triggered when the OK button is pressed), which is nice but i'm struggling to understand how i could use it to call a onSubmit() method inside the TodoForm.
For instance, it looks like this:
<b-modal id="todo-form-modal" #ok="something">
<todo-form />
</b-modal>
Ideally, the #ok="something" should call a method inside the TodoForm component.
How can I achieve this the right way ?
Expanding on #mapawa's answer:
<template>
<b-modal ... #ok="handleOk">
<todo-form ref="todoform" ...></todo-form>
</b-modal>
</template>
<script>
import TodoForm from 'somewhere/todoform'
export default {
components: { TodoForm },
methods: {
handleOk(bvEvt) {
// This assumes the root element of the todo form is the <form>
this.$refs.todoform.$el.submit()
// Alternatively, if your Todo Form exposes a submit method
this.$refs.todoform.submit()
}
}
}
</script>
What you want to do is to reference the parent component in the child component. You can use the ref attribute for this. I can't possibly explain this better than the official docs, so take a look at this.

Global header - use back button [duplicate]

In Ionic 1, we have the ability to define an <ion-nav-bar> above an <ion-nav-view>, which serves as a generic nav bar for the entire app and we could turn it off on a per-view basis (using ionNavView's hideNavBar=true|false.
It appears in Ionic 2 we have to insert an <ion-nav-bar> per page - and cannot have a global nav bar for the entire app. Is that correct, or am I missing a trick?
If so - it seems like a lot of duplicated code?
Also, it appears you do not have the ability for the NavBar to build its own back button, and you have to write the own mark-up for the back button yourself (per page) which, again, seems like a lot of code duplicate.
UPDATE:
Just like #mhartington says:
There is no way to create a global ion-navbar, as this is done on
purpose. The point of having a navbar defined for each component is so
that we can properly animate the titles, navbar background color (if
you change them) and animate other properties needed.
And about creating a custom directive to avoid duplicating ion-navbar html code:
That will still creat errors with how angular2 content projection
works. We have several issues that have been open when people try this
and the best answer is to not do it.
NOT recommended solution:
In order to avoid duplicating so much code, you can create your own custom component for the navbar.
Create a navbar.html with this code:
<ion-navbar *navbar>
<ion-title>MyApp</ion-title>
<button menuToggle="right" end>
<ion-icon name="menu"></ion-icon>
</button>
<ion-buttons *ngIf="!hideCreateButton" end>
<button (click)="createNew()"><ion-icon name="add"></ion-icon></button>
</ion-buttons>
</ion-navbar>
And then in the navbar.ts:
import {Component, Input} from '#angular/core';
import {NavController} from 'ionic-angular';
import {CreateNewPage} from '../../pages/create-new/create-new';
#Component({
selector: 'navbar',
templateUrl: 'build/components/navbar/navbar.html',
inputs: ['hideCreateButton']
})
export class CustomNavbar {
public hideCreateButton: string;
constructor(private nav: NavController) {
}
createNew(): void {
this.nav.setRoot(CreateNewPage, {}, { animate: true, direction: 'forward' });
}
}
By declaring the hideCreateButton as an input of the Component, you can decide in which pages show that button and in which ones should not be visible. So in this way, you can send information to tell the component how it should be, and customize it for each page.
So if you want to add the navbar in a page (without modifying the default template, so showing the create button) you just have to add the navbar element (binded to our custom component by us in the selector property):
<navbar></navbar>
<ion-content>
...
</ion-content>
And if you want to hide the create button (or modify you navbar like you want to) your page will look like this one:
<navbar [hideCreateButton]="hidebutton()"></navbar>
<ion-content>
...
</ion-content>
And remember that the hideButton() should be defined in your customPage.ts like this:
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
import {FORM_DIRECTIVES, FormBuilder, ControlGroup, Validators, AbstractControl } from '#angular/common';
#Component({
templateUrl: 'build/pages/create-new/create-new.html',
directives: [FORM_DIRECTIVES]
})
export class CreateNewPage{
private hideCreateButton: boolean = true;
public hidebutton(): boolean {
return this.hideCreateButton;
}
}
For ionic 3+
What I did to solve this was simply use a custom component.
ionic generate component navbar
Add the relevant navbar html to your component template
Add any other functionality to your component .ts file
Modify your selector to something relevant, (if used command above it
should just default to 'navbar'.
Also add the component to your app.module.ts declarations
Then in any of your page templates, simply use it as a custom element
e.g
<navbar></navbar>
<ion-content padding>
...
</ion-content/>
I had a similar issue creating an Ionic 4+ app (#ionic/angular 4.6.2), I wanted to add a login button and some other global stuffs in the header.
You can achieve that in a quite simple way.
Just add a ion-header containing a ion-toolbar in your app.component.html as a global header, like this:
<ion-header class="page-header">
<ion-toolbar id="main-toolbar">
<ion-title>
<ion-label>{{ pageTitle }}</ion-label>
</ion-title>
<!-- add here all the things you need in your header -->
</ion-toolbar>
</ion-header>
<ion-router-outlet id="content" main></ion-router-outlet>
The problem here is that the "global header" will overlay the content of any page if you do only that. So has a workaround just add an empty ion-header containing an empty ion-toolbar on top of all your pages before the content tag, as follow:
<ion-header>
<ion-toolbar></ion-toolbar>
</ion-header>
<ion-content>
<!-- your content here -->
</ion-content>
Doing that the "global header" will overlay the page header and the content will begin just after it.
Then you can manage all the code for your global header controls in your app.component.ts file.
I guess there could be some strange behaviour if the main header has a height greater than the "standard" toolbar height but with some nice CSS you should be able to fix it.
Furthermore, this workaround works fine with a side menu.
Hope it helps!
I have since found out this is not possible. The only way to achieve this is by providing an <ion-navbar> and that will handle the back button automatically.
E.g.:
<ion-navbar *navbar>
<button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Settings</ion-title>
</ion-navbar>
<ion-content padding class="hub-settings">
<!-- content here -->
</ion-content>

Render HTML in React Native

In my React Native app, I am pulling in JSON data that has raw HTML elements like this: <p>This is some text. Let’s figure out...</p>
I've added the data to a view in my app like this:
<Text>{this.props.content}</Text>
The problem is that the HTML comes out raw, it does not render like it would in a browser. Is there a way to get my JSON data to look like it would in a browser, inside my app view?
Edit Jan 2021: The React Native docs currently recommend React Native WebView:
<WebView
originWhitelist={['*']}
source={{ html: '<p>Here I am</p>' }}
/>
https://github.com/react-native-webview/react-native-webview
If you don't want to embed a WebView, there are also third party libraries to render HTML into native views:
react-native-render-html
react-native-htmlview
Edit March 2017: the html prop has been deprecated. Use source instead:
<WebView source={{html: '<p>Here I am</p>'}} />
https://facebook.github.io/react-native/docs/webview.html#html
Thanks to Justin for pointing this out.
Edit Feb 2017: the PR was accepted a while back, so to render HTML in React Native, simply:
<WebView html={'<p>Here I am</p>'} />
Original Answer:
I don't think this is currently possible. The behavior you're seeing is expected, since the Text component only outputs... well, text. You need another component that outputs HTML - and that's the WebView.
Unfortunately right now there's no way of just directly setting the HTML on this component:
https://github.com/facebook/react-native/issues/506
However I've just created this PR which implements a basic version of this feature so hopefully it'll land in some form soonish.
I found this component. https://github.com/jsdf/react-native-htmlview
This component takes HTML content and renders it as native views, with customisable style and handling of links, etc.
A pure JavaScript react-native component that renders your HTML into 100% native views. It's made to be extremely customizable and easy to use and aims at being able to render anything you throw at it.
react-native-render-html
Using this component will improve your application memory footprint and performance when compared to embedded WebViews.
Install
npm install react-native-render-html --save or yarn add react-native-render-html
Basic usage
import React from "react";
import { ScrollView, useWindowDimensions } from "react-native";
import RenderHTML from "react-native-render-html";
const html = `
<h1>This HTML snippet is now rendered with native components !</h1>
<h2>Enjoy a webview-free and blazing fast application</h2>
<img src="https://i.imgur.com/dHLmxfO.jpg?2" />
<em style="textAlign: center;">Look at how happy this native cat is</em>
`;
export default function App() {
// Allow images to scale to available width
// with contentWidth prop.
const { width } = useWindowDimensions();
return (
<ScrollView style={{ flex: 1 }}>
<RenderHTML contentWidth={width} source={{ html }} />
</ScrollView>
);
}
RenderHTML Props reference
You may customize the style of elements via class names, tags, and you can even register custom renders for tags. More info on the official website.
i uses Js function replace simply.
<Text>{item.excerpt.rendered.replace(/<\/?[^>]+(>|$)/g, "")}</Text>
React Native has updated the WebView component to allow for direct html rendering. Here's an example that works for me
var htmlCode = "<b>I am rendered in a <i>WebView</i></b>";
<WebView
ref={'webview'}
automaticallyAdjustContentInsets={false}
style={styles.webView}
html={htmlCode} />
<WebView ref={'webview'} automaticallyAdjustContentInsets={false} source={require('../Assets/aboutus.html')} />
This worked for me :) I have html text aboutus file.
import HTML from "react-native-render-html";
var htmlCode = "<b>I am <i>Italic</i></b>";
<HTML source={{html: htmlCode}}/>
The WebView component was not rendering for me HTML snippets, like
<b>hello</b>, world!
But if I would enclose the HTML snippet in a document, like the example below, then it did actually render the document:
<View style={styles.accContent}>
<WebView source={{html: `<!DOCTYPE html><html><body style="font-size: 3rem">${data.content}</body></html>`}} />
</View>