Question about simple situation, I want add vue modal component to default Laravel project.
When I registered in this way :
Vue.component('modal', {
template: '#modal-template'
})
new Vue({
el: '#app',
data: {
showModal: false
}
})
And named component like this :
ModalComponent.vue
Browser give me next errors.
All details in the Github repository
By the way, maybe better add modal window from bootstrap with jQuery or it will be messy?
you should have :
Vue.component('modal', require('./components/ModalComponent.vue'));
and inside your ModalComponent.vue file:
<template>
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
}
</script>
view.blade.php
<div id="app">
<button id="show-modal" #click="showModal = true">Show Modal</button>
<!-- use the modal component, pass in the prop -->
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
</modal>
</div>
Related
I have VUE Field and Form components which renders a form depending on dynamic data.
<template>
<form #submit="$emit('submit', $event)" >
<template v-for="(item, index) in form.elements">
<Field
v-model="value[index]"
:label="item.options.label"
:type="item.type"
/>
</template>
</form>
</template>
I can render a form by passing structure data
<Form :form="formStructure" v-model="state" #submit="save()" />
This renders the from elements with the order in the formStructure object
What I want to do is to add a decoration template to Form component and customize the view.
<Form :form="formStructure" v-model="state" #submit="save()" >
<template >
<div class="row">
<div class="col-4"><i class="icon-user"></i> <!-- Field component will be render here by Form componenet --> </div>
<div class="col-8"><i class="icon-mail"></i> <!-- Field component will be render here by Form componenet --> </div>
</div>
<h2>A Custom Header</h2>
<div class="row">
<!-- another row with other elements-->
</div>
</template>
</Form>
formStructure data is someting like
{
"form":{
"method":"post",
"id":"formF75a1543a"
},
"elements":{
"username":{
"type":"inputtext",
"options":{
"label":"Pick a username"
}
},
"email":{
"type":"inputtext",
"options":{
"label":"Your e-mail"
}
}
}
}
How can I achive this?
I found the answer after a long research. Slots are not enough to solve the problem. Teleport will do the trick.
<!-- The Form Component -->
<template>
<form #submit="$emit('submit', $event)" >
<slot name="default" ></slot>
<template v-for="(item, index) in form.elements">
<teleport :to="'#'+index" :disabled="!fieldTargetExists(index)">
<Field
v-model="value[index]"
:label="item.options.label"
:type="item.type"
/>
</teleport>
</template>
</form>
</template>
<!-- Using component with a template -->
<Form :form="formStructure" v-model="state" #submit="save()" >
<template >
<div class="row">
<div class="col-4"><i class="icon-user"></i> <span id="username"></span> </div>
<div class="col-8"><i class="icon-mail"></i> <span id="email"></span> </div>
</div>
<h2>A Custom Header</h2>
<div class="row">
<div id="submit"></div>
</div>
</template>
</Form>
My Blade View 'chat.blade.php'
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading"</div>
<div class="panel-body">Chats
<chat-messages :messages="messages"></chat-messages>
</div>
<div class="panel-footer">
<chat-form
v-on:messagesent="addMessage"
:user="{{ Auth::user() }}"
></chat-form>
</div>
</div>
</div>
</div>
</div>
#endsection
This code is extend from app.blade.php, which probably its not really the main focus of the problem
and here is My 2 Component From My Vue JS
'ChatMessages.vue'
<template>
<ul class="chat">
<li class="left clearfix" v-for="message in messages">
<div class="chat-body clearfix">
<div class="header">
<strong class="primary-font">
{{ message.user.name }}
</strong>
</div>
<p>
{{ message.message }}
</p>
</div>
</li>
</ul>
</template>
<script>
export default {
props: ['messages']
};
</script>
and here is the 'ChatForm.vue'
<template>
<div class="input-group">
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Type your message here..." v-model="newMessage" #keyup.enter="sendMessage">
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendMessage">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user'],
data() {
return {
newMessage: ''
}
},
methods: {
sendMessage() {
this.$emit('messagesent', {
user: this.user,
message: this.newMessage
});
this.newMessage = ''
}
}
}
</script>
and here is the following screenshot of the problem
Click here for the Picture
as you can see in the screenshot, the chat component from vue.js listed below, wont show up, its just appear blank, only displaying scrollbar,navbar and 'Chats' text. which is came from app.blade.php]
Please help me :). Thanks
You do not commit any messages to your component. :messages="messages" is Vue syntax.
Assuming your controller assigns $messages to your view:
<chat-messages messages="{{ json_encode($messages) }}"></chat-messages>
should do it. You need to use blade variables to assign
As the title implies I want to add two modal dialog's on one page.
I figured out how to create on but the second one I am having troubles with.
HTML:
<body>
<h1>-projects-</h1>
<ul id="button-container">
<li>
<a id="html-modal-button" #click="showModal = true">
<img class="htmllogo" src="images/HTMLLogo.png">
<div class="html-text-block">
<h2>HTML</h2>
<p>My web projects</p>
</div>
</a>
<htmlmodal v-if="showModal" #close="showModal = false"></htmlmodal>
</li>
<li>
<a id="cs-modal-button" #click="showModal = true">
<img class="csharplogo" src="images/CSHARPLogo.png">
<div class="cs-text-block">
<h2>C#</h2>
<p>My windows projects</p>
</div>
</a>
<csmodal v-if="showModal" #close="showModal = false"></csmodal>
</li>
</ul>
<!-- MODAL SECTION -->
<script type="text/x-template" id="html-modal-template">
<transition name="html-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">HTML HEADER</slot>
</div>
<div class="modal-body">
<slot name="body">HTML BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">HTML FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<script type="text/x-template" id="cs-modal-template">
<transition name="cs-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">CS HEAD</slot>
</div>
<div class="modal-body">
<slot name="body">CS BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">CS FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
</body>
</html>
VUE.JS:
$(window).load(function(){
// CREATE THE DOM COMPONENT
Vue.component('htmlmodal', {
template: '#html-modal-template',
});
Vue.component('csmodal', {
template: '#cs-modal-template',
});
// START THE APP
new Vue({
el:'#button-container',
data: {
showModal: false
}
})
});
**The Fiddle: ** https://jsfiddle.net/oz053uzj/
As you can see I have separated the modal section, so essentially I could simply create and edit a modal, create a vue.component and reference it.
The problem comes when I try to open the modal, it seem's to only open the second or last modal for each of the buttons, I presume its due to #click="showModal = <>" is same for both the modals, but I'm left clueless..
because their v-if is based on the same data showModal.
If showModal is true, both will be displayed. And the last one will be on top.
So how about differentiating them based on a string instead of true/false ?
<a id="html-modal-button" #click="showModal = 'html-modal'">
and
<htmlmodal v-if="showModal === 'html-modal'" ...
?
demo: https://jsfiddle.net/jacobgoh101/oz053uzj/1/
You should use two different variable for two modal.
HTML:
<body>
<ul id="button-container">
<li>
<a id="html-modal-button" #click="showModal = true">
First Modal
</a>
<htmlmodal v-if="showModal" #close="showModal = false"></htmlmodal>
</li>
<li>
<a id="cs-modal-button" #click="showCsModal = true">
Second Modal
</a>
<csmodal v-if="showCsModal" #close="showCsModal = false"></csmodal>
</li>
</ul>
<!-- MODAL SECTION -->
<script type="text/x-template" id="html-modal-template">
<transition name="html-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">HTML HEADER</slot>
</div>
<div class="modal-body">
<slot name="body">HTML BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">HTML FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<script type="text/x-template" id="cs-modal-template">
<transition name="cs-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">CS HEAD</slot>
</div>
<div class="modal-body">
<slot name="body">CS BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">CS FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
</body>
VUE.JS:
new Vue({
el:'#button-container',
data: {
showModal: false,
showCsModal: false,
}
})
**The Fiddle: ** https://jsfiddle.net/tanvir86/od2cjtkc/
I have a modal component which take a trigger to open the modal, and the content to go inside the modal.
<Modal>
<button className="btn btn--primary">Open modal</button>
<div>
<p>Modal content</p>
<p>More modal content</p>
</div>
</Modal>
And in the Modal component:
return (
<div className="Modal">
{props.children[0]}
<div className="Modal__container">
<div className="Modal__header">
<button className="Modal__close btn btn--secondary btn--small">
Close
</button>
<h1 className="Modal__heading">Here is my modal</h1>
</div>
<div className="Modal__content">{props.children[1]}</div>
</div>
</div>
);
This is working but very fragile as Im using an index on props.children. Can I instead name the components I pass to Modal? So something like:
<Modal>
<Modal.Trigger>
<button className="btn btn--primary">Open modal</button>
</Modal.Trigger>
<Modal.Content>
<p>Modal content</p>
<p>More modal content</p>
</Modal.Content>
</Modal>
I suggest you use props instead:
declare your Modal like so:
<Modal action={<button className="btn btn--primary">Open modal</button>}>
<div>
<p>Modal content</p>
<p>More modal content</p>
</div>
</Modal>
and your render method will then look something like
return (
<div className="Modal">
{props.action}
<div className="Modal__container">
<div className="Modal__header">
<button className="Modal__close btn btn--secondary btn--small">
Close
</button>
<h1 className="Modal__heading">Here is my modal</h1>
</div>
<div className="Modal__content">{props.children[1]}</div>
</div>
</div>
);
You can mark your children with a boolean flag that will serve as a name.
Within Modal you find the child marked as trigger and the child marked as content:
// within Modal
render() {
let trigger, content;
React.Children.forEach(this.props.children, child => {
if (!child) return;
if (child.props.trigger) { trigger = child }
if (child.props.content) { content = child }
})
return (
<div className="Modal">
{trigger}
<div className="Modal__container">
<div className="Modal__header">
<button className="Modal__close btn btn--secondary btn--small">
Close
</button>
<h1 className="Modal__heading">Here is my modal</h1>
</div>
<div className="Modal__content">
{content}
</div>
</div>
)
}
And you mark the appropriate children when rendering Modal:
<Modal>
<button trigger className="btn btn--primary">Open modal</button>
<div content>
<p>Modal content</p>
<p>More modal content</p>
</div>
</Modal>
We wrote a library called seapig that you might find useful for this use case.
When I wrap a form with jquery geocomplete in a Vue modal, the geocomplete stops working. I'm not sure how to fix it so that geocomplete works when the modal is active.
Here is a working example without Vue or a modal:
https://jsfiddle.net/3gzovugy/68/
Here is the same example, wrapped in the vue site's example modal, that won't geocode. Any suggestions?
https://jsfiddle.net/3gzovugy/96/
<div id="app">
<button id="show-modal" #click="showModal = true">Show Modal</button>
<modal v-if="showModal" #close="showModal = false">
<div slot="body">
<form>
<div class="item">
<input id="autocomplete" placeholder="Look up your address" type="text">
</div>
<div class="item">
<input class="cat_textbox" id="houseNo" data-geo="street_number" type="text" placeholder="House Number" maxlength="50" />
</div>
<div class="item">
<input class="cat_textbox" id="street" data-geo="route" type="text" placeholder="street" maxlength="50" />
</div>
<div class="item">
<input class="cat_textbox red" id="BillingAddress" data-geo="street_address" type="text" placeholder="Billing Address" maxlength="50" name="BillingAddress" />
</div>
</form>
</div>
</modal>
</div>
<template id="modal-template">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
I see your geocomplete related code is in $(document).ready(function(). Taking inspiration from this answer, you can move code inside document.ready to one of the lifecycle hooks for this purpose. You can try using mounted as it comes pretty close to $(document).ready():
Vue.component('modal', {
template: '#modal-template',
mounted () {
$("#autocomplete").geocomplete({
details: "form div",
detailsAttribute: "data-geo",
types: ["(cities)"],
componentRestrictions: {
country: "in"
}
});
}
})
With these changes, you code starts to show suggestion: check here. You may need some other UI changes to see the geocomplete dropdown on top.