How to execute x-data commands in alpine js library when out of state? - alpine.js

How do I expand the div when the button is out of state?
<div x-data="{ open: false }">
<span x-show="open">
Content...
</span>
</div>
<button #click="open = true">Expand</button>

one way would be to keep the state in the global $store
<script>
document.addEventListener('alpine:init', () => { Alpine.store("mystate", { open: false })})
</script>
<div x-data>
<span x-show="$store.mystate.open">
Content...
</span>
</div>
<button x-on:click="$store.mystate.open = !$store.mystate.open">Toggle</button>

Related

OnClick of Button , Need to Display the Modal using React Typescript

I have two Components, onClick on Button from "Button Component", I need to Perform Open & Close Operations of that Modal,
But my Modal is in "Dropdown component"... There is No Relation between Button and Dropdown Components, Now How Can I send Onclick event from "Button Component" to "Dropdown component" , and use there to Perform Open & Close Operations of that Modal...
My Button Component
const Button:React.FC = () => {
const [cancel, setcancel] = useState<boolean>(false)
const onCancel=(event: React.MouseEvent<HTMLButtonElement>)=>{
setcancel(true);
}
return (
<button className='btn btn-dark' onClick={onCancel}>Button</button>
)
}
export default Button
My Dropdown component
const Dropdown: React.FC = () => {
const data = inputs;
return (
<>
<div className='form-group'>
<div className="col-4">
<select className="form-select" aria-label="Disabled select example">
<option selected>Select an Option</option>
{data.purpose.map((items) => (
//console.log(items.value);
<option>{items.value}</option>
))}
</select>
</div>
</div>
<div className="modal">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Modal title</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<p>Do YOu need any Changes</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" className="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</>
)
}
export default Dropdown
Here is APP.tsx
function App() {
return (
<div className="App">
<h1>LordShiva</h1>
<Dropdown />
<Button/>
</div>
);
}
export default App;
Make states in App.js
const [isModal,setIsModal] = UseState(false);
Now pass setIsModal in props of Button Component in your app.js file
<Button passedFunc={()=>setIsModal(!isModal)}/>
Now get this passedFunc in Button Component parameters in props and call it on onClick of button like onClick={() => props.passedFunc()}
Now pass isModal state in your DropDown Component,
<Dropdown show={isModal} />
Now get this show property in your dropdown components props.And then wrap the modal code like that :
{props.show ? <div className="modal">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Modal title</h5>
<button type="button" className="btn-close" data-
bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<p>Do YOu need any Changes</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary"
data-bs-dismiss="modal">Close</button>
<button type="button" className="btn btn-
primary">Save changes</button>
</div>
</div>
</div>
</div> : null}
Note: you can destructure props too.

Expand Collapse Icons with Vue Js and Bootstrap

I have a Bootstrap accordion with the expand collapse panels,which works fine.
But when expanded it should display minus icon which is not working well for me.
When I click to expand all the panel's icons are changed to minus instead of just changing the one which was expanded.
I have my code in the Vue JS template as below
Am calling the toggle function onclick to toggle the icons, but its doing it for all the other panels too.
How can I fix this? Thanks in advance.
Vue.component('accordion', {
data: function () {
return {
alerts: [],
sound: '',
collapsed:true
}
},
template: `
<div>
<div v-for="(alert, index ) in alerts" class="panel panel-default">
<div class="panel-heading" v-bind:style="'background-color:'+alert.color" role="tab" v-bind:id="'heading'+index" >
<a role="button" data-toggle="collapse" data-parent="#accordion"
v-bind:href="'#collapse'+index" aria-expanded="true" v-on:click="toggle">
<i id="collapseExpand" v-show="collapsed" class="more-less fa fa-plus"></i>
<i id="collapseExpand" v-show="!collapsed" class="more-less fa fa-minus"></i>
<h4 class="panel-title">#{{ alert.description }}</h4></a>
</div>
<div v-bind:id="'collapse'+index" class="panel-collapse collapse" role="tabpanel">
<div class="panel-body">
<div>#{{ alert.comment }}</div>
<div class="row">
<form v-bind:id="'form_'+index" v-bind:name="'form_'+index" v-bind:action="route" method="POST" style="display: inline;">
<input type="hidden" name="_token" :value="csrf">
<input type ="hidden" v-bind:id="'trigger_id_'+alert.triggerid" name = "trigger_id" v-bind:value="alert.triggerid">
<div class="col-lg-12">
<div class="input-group">
<input type="text" v-bind:id="'ack_msg_'+alert.triggerid" name="ack_msg" class="form-control"
placeholder="Acknowledge Message...">
<span class="input-group-btn">
<button class="btn btn-primary" type="submit">Save</button>
</span>
</div>
</div>
</form>
</div>
</div>
<div class="panel-footer">#{{ alert.timestamp }}</div>
</div>
</div>
<input type="hidden" id="audioFile" name="audioFile" v-bind:value="sound">
</div>`,
mounted: function () {
this.loadData();
setInterval(function () {
this.loadData();
}.bind(this), 1000);
},
methods: {
loadData: function () {
$.get('{{ route('getAlertsPersistent') }}', function (response) {
this.alerts = response;
this.sound = this.alerts[0].sound
}.bind(this));
},
toggle(){
this.collapsed = !this.collapsed ;
}
},
});
new Vue({el: '#accordion'});
You want to separate your accordion item that you want to loop. In that way you can have isolated states in each component.
<div>
<accordion-item
v-for="(alert, index) in alerts"
:alert="alert"
:key="index">
</accordion-item>
</div>
inside your <accordion-item/> you should have collapsed inside your data
The other way around is storing the toggled items in array.
export default {
data: () => ({
toggled: []
}),
methods: {
isActive (item) {
return this.toggled.indexOf(item) >= 0
},
toggleItem (item) {
const index = this.toggled.indexOf(item)
if (index >= 0) {
this.toggled.splice(index, 1)
return
}
this.toggled.push(item)
}
}
}
So you can use it now as follows
<a
role="button"
data-toggle="collapse"
data-parent="#accordion"
v-bind:href="'#collapse'+index"
aria-expanded="true"
v-on:click="toggleItem(index)">
<i
:class="[isActive(index) ? 'fa-minus' : 'fa-plus']"
class="more-less fa"></i>
<h4 class="panel-title">#{{ alert.description }}</h4>
</a>
btw you're looping an id=collapseExpand which will cause you problem. instead try :id="'collapseExpand' + index"

Laravel/VueJs. How can I display button with different color based on column value passed in?

I'm looping through user table. And each user table has a button that toggle(update:Boolean type) user status on user table. And I want the button for each user to have red color when the status value for the user is 0 and green when the status is 1. Also I want the button to change the color(LIVE) based on the status value each time it clicked.
component: ToggleStatus.vue
<template>
<div>
<button type="button" v-bind:class="buttonStatus" #click="goOnline">
<span class="ion-ios-wifi" ></span>
</button>
</div>
</template>
<script>
export default {
props: ['userId', 'onlinestat'],
mounted() {
console.log('Component mounted.')
},
data: function() {
return {
status: this.onlinestat,
}
},
methods: {
goOnline() {
axios.post('/reservation/online/' + this.userId )
.then(response => {
this.status =! this.status;
console.log(response.data);
})
.catch(errors => {
if (errors.response.status == 401){
window.location = '/login';
}
});
}
},
computed: {
buttonStatus() {
return(this.status) ? 'btn btn-outline-danger text-danger' : 'btn btn-success ';
}
}
}
</script>
Controller:
$authUser = Auth::user()->business_id;
$employee = User::where('business_id', $authUser)->get()->sortBy('name');
return view('backend.reservation.index', compact('employee'));
View/Blade
<div class="container-fluid flex-grow-1 container-p-y">
<div class="uikit-example">
<div class="row">
#foreach ($employee as $key => $emp)
<div class="col-lg-4 col-md-4 col-sm-12">
<div class="card mb-4">
<div class="card-body">
<div class="media align-items-center">
<img src="{{ asset('Upload/Images/Media/Avatar/Thumb/'.$emp->image) }}" alt class="ui-w-60 rounded-circle">
<div class="media-body pt-2 ml-3">
<h5 class="mb-2">{{ $emp->name }}</h5>
<div class="text-muted small mb-2">{{ $emp->phone }}</div>
<div class="text-muted small mb-2">{{ $emp->email }}</div>
<div class="text-muted small mb-2"><span>ID: </span>{{ $emp->user_code }}</div>
</div>
<div class="">
<toggleonline user-id="{{ $emp->id }}" onlinestat="{{ $emp->onlinestatus }}"></toggleonline>
</div>
</div>
</div>
<div class="card-footer text-center py-3">
{{-- + Go Online --}}
{{-- <span class="ion ion-md-mail"></span> --}}
{{-- <div class="float-right"> --}}
My Reservations
{{-- </div> --}}
</div>
</div>
</div>
#endforeach
</div>
</div>
</div>
The result I'm getting is that the button does toggle but the toggle button of all the user come red after on refresh page or when the page loads.
try
buttonStatus() {
return(this.status==0) ? 'btn btn-outline-danger text-danger' : 'btn btn-success ';
}

Call method other component in vue

How to call method other component in Vue?
I have component HeaderSearch
<template>
<form action="">
<div class="form-group">
<div class="input-group">
<span class="input-group-btn">
<button class="btn" type="button">
<i class="fa fa-search"></i>
</button>
</span>
<input type="text" #keyup="search(keyword)" v-model="keyword" class="form-control" placeholder="Search...">
</div>
</div>
</form>
</template>
<script>
export default {
data(){
return { keyword: "" };
},
methods: {
search: function(keyword){
if(keyword == ''){
// Want call method fetchPost in PostHome component here
}else{
}
}
}
}
</script>
And I have component PostHome
<template>
<div>
<div class="box r_8 box_shadow" v-for="post in posts">
<div class="box_header">
<a :href="post.url">
<h3 class="mg_bottom_10" v-text="post.title"></h3>
</a>
<small v-text="post.description"></small>
<a :href="post.url" class="box_header_readmore">Read more</a>
</div>
<div class="box_body">
<a :href="post.url" v-show="post.thumbnail">
<img :src="post.thumbnail" class="img_responsive" style="min-height: 300px;background-color: #f1f1f1;
">
</a>
</div>
<div class="box_footer" v-show="post.tags.length > 0">
<ul>
<li v-for="tag in post.tags">
<a v-text="tag.name" href="javascript:void(0)"></a>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
posts: null,
}
},
methods: {
fetchPosts: function(){
var url = base_url + '/user/posts'
this.$http.get(url).then(res => {
this.posts = res.data;
});
}
},
created: function(){
this.fetchPosts();
}
}
</script>
I want when user type keyup to search then if
keyword == ''
call method fetchPost method in PostHome component
You can use Mixins if that method is reusable.
Reference: https://v2.vuejs.org/v2/guide/mixins.html

How to define extra button in fine uploader template that will trigger its own end action

I want to have
- a text field and a button. Upon click of button text data will need to posted to endpoint.
The text field and button will repeat for each file in the uploader.
Below my attempt, and it is not working properly in all the cases and want to get to better solution.
The text field: qq-edit-caption
The button: qq-upload-update-caption
The button acts as delete button with selector 'qq-upload-delete-selector' and to differentiate I set a flag true on the onclick action (crappy I know!).
I read lot about creating 'extraButton' and all it talks about(as per my understanding) creating additional upload button, buy I need button on each file like DELETE and CANCEL,and not sure how I can cleanly implement the solution. Any help is much appreciated.
My template
<div class='qq-uploader-selector qq-uploader' qq-drop-area-text='Drop files here'>
<div class='qq-total-progress-bar-container-selector qq-total-progress-bar-container'>
<div role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' class='qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar'></div>
</div>
<div class='qq-upload-drop-area-selector qq-upload-drop-area' qq-hide-dropzone>
<span class='qq-upload-drop-area-text-selector'></span>
</div>
<div class='buttons'>
<div class='qq-upload-button-selector qq-upload-button'>
<div>Select files</div>
</div>
<button type='button' id='trigger-upload-section<?php echo $ind; ?>' class='btn btn-primary file-section-button'>
<i class='icon-upload icon-white'></i> Upload
</button>
</div>
<span class='qq-drop-processing-selector qq-drop-processing'>
<span>Processing dropped files...</span>
<span class='qq-drop-processing-spinner-selector qq-drop-processing-spinner'></span>
</span>
<ul class='qq-upload-list-selector qq-upload-list' aria-live='polite' aria-relevant='additions removals'>
<li>
<div class='qq-progress-bar-container-selector'>
<div role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' class='qq-progress-bar-selector qq-progress-bar'></div>
</div>
<span class='qq-upload-spinner-selector qq-upload-spinner'></span>
<div class="filewrapper">
<div class="filecontainer">
<div class="filecontent">
<img class='qq-thumbnail-selector' qq-max-size='80' qq-server-scale>
</div>
<span class="qq-upload-file-selector qq-upload-file filename"></span>
</div>
<div class="filesidebar">
<!--span class='qq-upload-caption-selector qq-upload-caption'></span-->
<!--span class='qq-edit-caption-icon-selector qq-edit-caption-icon kk-editable' aria-label='Edit caption'></span-->
<input class='qq-edit-caption-selector qq-edit-caption kk-editing' placeholder='Enter Caption here ...' onchange='captionUpdate();'>
</div>
<div class="filesidebar2">
<button type='button' class='qq-btn qq-upload-delete-selector qq-upload-update-caption file-section-button btn-primary' onclick='captionUpdate(true);' title='Caption Update' disabled><i class='icon-pencil icon-white'></i></button>
<button type='button' class='qq-btn qq-upload-cancel-selector qq-upload-cancel'>Cancel</button>
<button type='button' class='qq-btn qq-upload-retry-selector qq-upload-retry'>Retry</button>
<button type='button' class='qq-btn qq-upload-delete-selector qq-upload-delete file-section-button btn-primary' onclick='captionUpdate(false);' title='Delete File'><i class='icon-trash icon-white'></i></button>
</div>
<span role='status' class='qq-upload-status-text-selector qq-upload-status-text'></span>
<div class="fileclear"></div>
</div>
</li>
</ul>
<dialog class='qq-alert-dialog-selector'>
<div class='qq-dialog-message-selector'></div>
<div class='qq-dialog-buttons'>
<button type='button' class='qq-cancel-button-selector'>Close</button>
</div>
</dialog>
<dialog class='qq-confirm-dialog-selector'>
<div class='qq-dialog-message-selector'></div>
<div class='qq-dialog-buttons'>
<button type='button' class='qq-cancel-button-selector'>No</button>
<button type='button' class='qq-ok-button-selector'>Yes</button>
</div>
</dialog>
<dialog class='qq-prompt-dialog-selector'>
<div class='qq-dialog-message-selector'></div>
<input type='text'>
<div class='qq-dialog-buttons'>
<button type='button' class='qq-cancel-button-selector'>Cancel</button>
<button type='button' class='qq-ok-button-selector'>Ok</button>
</div>
</dialog>
</div>
Caption Update Button Click:
uploaderContainer.addEventListener('click', function(event) {
isCaptionUpdateClick = false;
if (event.target.className.indexOf('icon-pencil') >= 0) {
isCaptionUpdateClick = true;
};
});
My Delete Parameter setup:
deleteFile: {
enabled: true,
method: "POST",
endpoint: "/ci/fine/endpoint",
params: {
qqcaptionupdate: function() {
if (isCaptionUpdateClick === true) {
return 'YES';
}
},
qqcaption: function() {
return captionValue;
},
bookid: function() {
return $("#book_id").val();
},
sectionid: function() {
return $('#'+uploaderInfo.sectionIdSelector+'').val();
},
}
}

Resources