Everytime I insert tag in my main app it always rendering a new line, couldn't it be inline? I want to achieve something like this :
<p>This is a component :<component></component></p>
<!--worked with other html tags-->
Result instead :
This is a component :
component content
Of course I can insert prefix This is a component : as props in the component so it can be inline, at least for displaying, but that's not always I intended to be..
I wonder also where Vue store css template for component.
Thanks community.
Your component isn't rendering on a new line. It is rendering based on the rendering rules for HTML. If your component's root tag is a block element, then it will be rendered on the next line. If it is an inline element, then it will be rendered inline.
console.clear()
const Inline = {
template: `<span>This is inline</span>`
}
const Newline = {
template: `<div>This is on a new line</div>`
}
new Vue({
el: "#app",
components: {
Inline,
Newline
}
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
<p>This is an inline component:
<component is="Inline"></component>
</p>
<p>This is a block component:
<component is="Newline"></component>
</p>
</div>
In the above example, the Inline component's root tag is a span. Spans are inline elements. The Newline component's root tag is a div. Divs are block level elements and the text is on the next line.
You could also use display: inline on a div and cause the component to be rendered inline.
console.clear()
const Newline = {
template: `<div style="display: inline">This is on the same line</div>`
}
new Vue({
el: "#app",
components: {
Newline,
}
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
<p>This is a block component that displays inline:
<component is="Newline"></component>
</p>
</div>
The HTML rendered by Vue follows all the layout rules of HTML you hand write. There's no magic involved.
Related
Basically, I'm creating a form component that is contained inside a v-dialog. The form component will have different child components that are rendered based on select input. So I have to set width of v-dialog to "unset", so that the width of the dialog will stretch to match its content.
The transition works when I toggle the value of width, eg: either 450px or 300px. The problem is that I don't know beforehand the width of the form contains in the dialog, so I definitely need to use dynamic width.
So far, I can not find anyways to achieve transition when using dynamic width. I was trying to get the width of the form component using refs, but setting width to unset, prevent the transition. By the way, the transition I'm talking about is the transition of the width, when using fixed width, it shows nice transition but not for dynamic width
<div id="app">
<v-app id="inspire">
<div class="text-center">
<v-dialog v-model="dialog" width="unset">
<template v-slot:activator="{ on }">
<v-btn color="red lighten-2" dark v-on="on">
Click Me
</v-btn>
</template>
<v-card>
<v-select v-model="selectedForm" :items="items">
</v-select>
<div v-if="selectedForm==='form-a'" class='form-a'>FormA</div>
<div v-if="selectedForm==='form-b'" class='form-b'>FormB</div>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text #click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</v-app>
</div>
new Vue({
el: "#app",
vuetify: new Vuetify(),
data() {
return {
selectedForm: "form-a",
items: ["form-a", "form-b"],
dialog: false
};
}
});
codepen for using fixed width: https://codepen.io/duongthienlee/pen/MWaBLXm
codepen for using dynamic width: https://codepen.io/duongthienlee/pen/GRpBzmL
Noted that in the example i made in codepen, I defined width already, but the real case is that I don't know beforehand the width of form-a and form-b component. form-a and form-b width will be inherited by its parent div which is v-dialog, so that's why I set the width of v-dialog to be unset.
An example of what I mean "dynamic width": form-a has a select input. When user chooses an item, there will be a request to server to get input labels. So form-a will render multiple input fields based on the response body from server. The response body will contain label and default values information. So that makes the width of form-a becomes dynamic.
I think something like this can work for you.
Change v-dialog like so:
<v-dialog v-model="dialog" :width="forms.find(x => x.name===selectedForm).width">
Modify data() to return a forms prop:
data() {
return {
selectedForm: "form-a",
items: ["form-a", "form-b"],
dialog: false,
forms: [
{
name: 'form-a',
width: 200
},
{
name: 'form-b',
width: 1000
}
]
};
}
What you want to do is get the size of the rendered form, and then apply it to the dialog.
This is a common theme when attempting to animate content with dynamic dimensions.
One way to do this is by:
Set the form's visibility as hidden
Wait for it to render
Get the form's width and set it to the dialog
Unset the form's visibility
The tricky/hacky part is that you have to properly await DOM (setTimeout) and Vue ($nextTick) recalculations. I didn't have to await for Vue's $nextTick in this example, but you probably will if you're rendering nested form components:
<div class="form-container">
<div :style="formStyle('form-a')" class='form-a' ref="form-a">FormA</div>
<div :style="formStyle('form-b')" class='form-b' ref="form-b">FormB</div>
</div>
computed:{
formStyle(){
return form => ({
visibility: this.selectedForm == form ? 'inherit' : 'hidden',
position: this.selectedForm == form ? 'inherit' : 'absolute'
})
}
},
methods: {
async onSelectChange(form){
// async request
await new Promise(resolve => setTimeout(resolve, 1000))
this.selectedForm = form
this.recalculate()
},
async recalculate(){
// wait for DOM to recalculate
await new Promise(resolve => setTimeout(resolve))
const formEl = this.$refs[this.selectedForm]
this.dialogWidth = formEl.clientWidth
this.dialogHeight = formEl.clientHeight
},
...
}
Here's the working code to give you an idea:
https://codepen.io/cuzox/pen/yLYwoQo
If I understand you correctly, then this can be done using css. You can try replace all the fix width in the form with
width: fit-content;
For example in you codepen:
.form-a {
width: fit-content;
height: 350px;
background: blue;
}
.form-b {
width: fit-content;
height: 500px;
background: red;
}
The v-dialog renders into a div with class v-dialog:
It seems the animation only works when the the width is of known value, so it cannot be just "unset". The solution would be to get the width of the child element, and set the width of the v-dialog accordingly with a variable.
See VueJS get Width of Div on how to get the width of the child element.
Let me know if it works, I find this is very interesting.
What I want to do is to insert a component inside a div, after a specific div with a specific class name. How do I do this in typescript?
<div class ="{{order.orderId}}">
<div class="enter-here"></div>
<other html elements here>
</div>
And TypeScript:
insertDiv(){
insert.component.after.className.enter-here;
}
Inserting new element is not the angular way of doing it, when using angular DOM manipulation should be avoided as much as possible. In your question you haven't mentioned what will be the contents of .enter-here, so I am assuming it is just plain text:
In your html:
<div class ="{{order.orderId}}">
<div *ngIf="showEnterHereDiv" class="enter-here">
some text or list which should be visible after showDiv is called
</div>
<other html elements here>
</div>
In your typescript:
// hidden by default
showEnterHereDiv: boolean = false;
...
showDiv() {
// call this method to show the div
this.showEnterHereDiv = true;
}
hideDiv() {
this.showEnterHereDiv = false;
}
I am new to react and I have a react component structure like:
<MainComponent>
<Button />
<Content />
</MainComponent>
Now when I click on the Button, I need to replace the existing div (say div1) of the Content component with another div (div2). Can you please tell me how to do it. Thank you.
Note: Till now, on click event I have been changing the data of the single div using state and prop. Now I got to replace the whole div with another one.
Like this.
render() {
var returnIt;
if (useDivOne) returnIt = (<div id='one'></div>);
else returnIt = (<div id='two'></div>);
return (returnItj);
}
If this is your structure:
<MainComponent>
<Button />
<Content />
</MainComponent>
and Content renders something like:
<div>
this is div 1
</div>
I would think you would need to pass a prop to Content that would tell you which div to render, then in Content's Render you manipulate the properties of Boolean logic to present a different component:
class Content extends Component {
render() {
return(
{
!this.props.RenderDiv2Bool &&
<div>
This is Div1 and it will be rendered
because RednerDiv2Bool is false.
</div>
}
{
this.props.renderDiv2Bool &&
<div>
This is Div2 and it will be rendered
because RednerDiv2Bool is true.
</div>
}
)
};
}
Not necessarily better but just another way to do it.
I'm working with Angular directives that looks like this:
<parent>
<children></children>
<children></children>
<children></children>
</parent>
Parent directive has a
template: return "<div><ul></ul><div ng-transclude></div></div>"
And children directives will go inside that ng-transclude div.
My final HTML structure is
<newParent>
<div ng-transclude>
<child></child>
<child></child>
<child></child>
</div>
</newParent>
I wonder if it's possible to remove that ng-transclude div so that the new children are direct children of the new parent. (I have more children, a random number >1).
I have to do so to match an existing template so I cannot change its structure.
I actually have no Fiddles, if you need more information just ask. Thank you!
You can append the content yourself, without using ng-transclude, using the transclude function:
app.directive("parent", function($compile) {
return {
restrict: "EA",
transclude: true,
link: function(scope, element, attrs, ctrls, $transclude) {
$transclude(function(clone, scope) {
element.append(clone);
});
}
};
});
Here's more information about Transclusion.
Without a template, this will add the transcluded elements as only children of the directive. With the template, you'll need to properly place (e.g. insert it into a <div> after <ul>) the content yourself.
in every angular template we have to define a root html node, then inside it we can define the Html of our directive.
is there a way in angular to ignore that root node?
example :
my directive template :
<div class="space consuming div, and absolute positioning breaker">
<div class="content positioned relative to the directives parent 1"></div>
<div class="content positioned relative to the directives parent 2"></div>
<div class="content positioned relative to the directives parent 3"></div>
</div>
can we just set our template to be
<div class="content positioned relative to the directives parent 1"></div>
<div class="content positioned relative to the directives parent 2"></div>
<div class="content positioned relative to the directives parent 3"></div>
thanks!
You only need one root element if you are using replace: true in your template.
This is the case if you have defined custom element and are using then in your HTML in the following way:
<tabs>
<pane>1</pane>
<pane>2</pane>
</tabs>
In this case, replacing tabs with a template which has two roots will cause some confusion.
However, if you do not need replace: true, then you can set the directive on the element you want and assign a multi-root template on it. That template will be rendered inside the element which has the directive.
JS
var app = angular.module('plunker', []);
app.directive('myDirectiveOne', function() {
return {
template: '<p>Hello</p><p>World!</p>'
};
})
app.directive('myDirectiveTwo', function() {
return {
template: '<p>Hello</p><p>World!</p>',
replace: true
};
})
Template
<!-- works -->
<div my-directive-one></div>
<!-- has problem -->
<div my-directive-two></div>
E.g. http://plnkr.co/edit/jgEWsaxzfD4FkHcocJys?p=preview