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

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.

Related

Add and Remove dom elements using alpine JS

I am trying to build a custom add and remove entire div element from an array using alpine JS, here is my code which is working but instead of removing from the exact remove button click it will remove the last one on the array.
HTML
<div x-data="addRemove()">
<template x-for="(field, index) in fields" :key="index">
<div>
<input type="text" name="txt1[]" class="form-input">
<button type="button" class="btn btn-danger btn-small" #click="removeField(index)">×</button>
</div>
</template>
<button type="button" #click="addNewField()">+ Add Row</button>
</div>
JAVASCRIPT
return {
fields: [],
addNewField() {
this.fields.push({});
},
removeField(index) {
this.fields.splice(index, 1);
}
}
Found a solution, this is what I did.
HTML
<div x-data="addRemove()">
<template x-for="(field, index) in fields" :key="field.id">
<div>
<input type="text" name="txt1[]" class="form-input">
<button type="button" class="btn btn-danger btn-small" #click="removeField(field)">×</button>
</div>
</template>
<button type="button" #click="addNewField()">+ Add Row</button>
</div>
JAVASCRIPT
function addRemove() {
return {
fields: [],
addNewField() {
this.fields.push({id: new Date().getTime() + this.fields.length});
},
removeField(field) {
this.fields.splice(this.fields.indexOf(field), 1);
}
}
}
You've to set the 'key' with a unique value in the looping.
<div x-data="{data: []}">
<div #click="data.push({ randomNumber: new Date().getTime()})">(Click Here To Add New Data)</div>
<template x-for="(item, index) in data" :key="index">
<div>
<span x-text="item.randomNumber"></span>
<span #click="data.splice(index, 1)">Remove</span>
</div>
</template>
</div>
online test: https://codepen.io/yuxufm/pen/YzLoxvE

Getting a modal to pop up when validation is false

I'm trying to create a page that when you click on add product button a modal pops up with a form that gets filled out.
What I'm trying to do is after you've submitted the form and there are errors then I would like for it to redirect back
and have the modal popup with the error messages.
Here is my code
My controller
public function addProduct(Product $product)
{
$validator = Validator::make(request()->all(), [
'title' => 'required'
]);
if($validator->fails())
{
return redirect()->back()->with([
'errors' => $validator->errors()
])
}
}
My blade file
<button type="button" class="btn btn-sm btn-success" data-toggle="modal" data-target="#addProductModal">
<i class="fa fa-plus"></i> Add Product
</button>
#include('admin.product.add-product')
and this is my modal
<div class="modal fade" id="addProductModal" tabindex="-1" aria-labelledby="addProductModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addProductModalLabel">Add a Product</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form action="{{ route('admin.product.addProduct') }}" method="post">
#csrf
<div class="modal-body">
<div class="form-group">
<label for="name">Name</label>
<input type="text" name="name" class="form-control">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-success">Save changes</button>
</div>
</form>
</div>
</div>
</div>
You can achieve that using sessions.
I'm using Form Requests for validation, and in my CreateCategoryRequest I added:
public function withValidator($validator)
{
if ($validator->fails()) {
\Session::flash('create_category_error', 'Create category validation failed!');
}
}
In blade:
#if (session('create_category_error'))
<script type="text/javascript">
$('#myModal').modal('show');
</script>
#endif
Yes it's that simple :P
Happy coding!
You can use this also.
<!-- Test if validation failed; hence show modal -->
#if($errors->getBag('default')->first('name') != '')
<script type="text/javascript">
$(document).ready(function(){
$("#addProductModal").modal('show');
});
</script>
#endif

vuejs stop propagation of click when clicked outer div

I am trying to create a search show hide feature. I have a click event that shows the search bar, but if I click somewhere in the put it get removed again. I tried with click.stop but it doesn't work. I am using vue.js inside a laravel project.
Here is my code
<template>
<div>
<div class="menu_srch d-flex" #click.stop="dos">
<i class="fa fa-search search_btn"></i>
<div class="header_serch " v-if="showSearch">
<div class="header_serch_input">
<input type="" name="" placeholder="Search">
</div>
<div class="header_serch_i">
<i class="fa fa-search"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
showSearch : false,
}
},
methods: {
dos(){
this.showSearch = !this.showSearch
}
},
}
</script>
using click.self doesn't even work.. dos method doesn't run when click.self is used.
Vue.js version : "^2.6.11"
You can capture the click event end to stop the propagation one level down.
<template>
<div>
<div class="menu_srch d-flex" #click="dos">
<i class="fa fa-search search_btn"></i>
<div #click.stop class="header_serch" v-if="showSearch">
<div class="header_serch_input">
<input type name placeholder="Search">
</div>
<div class="header_serch_i">
<i class="fa fa-search"></i>
</div>
</div>
</div>
</div>
</template>
Or you need to restructure your template.
<template>
<div>
<div class="menu_srch d-flex" #click="dos">
<i class="fa fa-search search_btn"></i>
</div>
<div class="header_serch" v-if="showSearch">
<div class="header_serch_input">
<input type name placeholder="Search">
</div>
<div class="header_serch_i">
<i class="fa fa-search"></i>
</div>
</div>
</div>
</template>

Can't pass Vue variable to hidden input v-model in view(v-for)

I'm new to Vue JS and I'm building an application with Laravel Spark and trying to utilize Vue as much as possible.
I have a form to simply add an 'Asset Type' with a component. Once the Asset Type is successfully created, a list of properties is grabbed from the database and set to a 'data' attribute. In my view(I'm using an inline template), I have a 'v-for' that creates a form for each property that has two hidden inputs for the property id and the type id, and one "Add" button that assigns the property to the newly created type.
THE PROBLEM:
I can't seem to assign the value of the hidden inputs within the view while using v-models. When I submit one of the forms, the form request data always returns the initial data value from the new SparkForm object.
In other words, I need to assign the hidden input values within the v-for loop in the view.
Here's my component:
Vue.component('new-asset-type', {
props: [],
data() {
return {
// type_id: this.type_id,
properties: this.properties,
newAssetType: new SparkForm({
label: null,
enabled: false,
}),
assignPropForm: new SparkForm({
prop_id: "",
type_id: "",
}),
};
},
methods: {
createType: function () {
Spark.post('/asset-types', this.newAssetType)
.then(response => {
this.type_id = response.type_id;
axios.get('/getTypeNotProps/' + this.type_id).then((response) => {
this.properties = response.data;
console.log(this.properties);
});
})
.catch(response => {
console.log("fail");
});
},
assignProp: function () {
Spark.post('/asset-properties/add', this.assignPropForm)
.then(response => {
console.log(response);
})
.catch(response => {
console.log("fail");
});
}
}
});
And here's my view:
#extends('spark::layouts.app')
#section('content')
<new-asset-type inline-template>
<div class="container">
<!-- Application Dashboard -->
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Add a New Asset Type</div>
<div class="panel-body" id="addTypeForm">
<div class="form-horizontal">
<div class="form-group" :class="{'has-error': newAssetType.errors.has('label')}">
{{ Form::label('label', 'Label', ['class' => 'col-md-4 control-label']) }}
<div class="col-md-6" >
<input type="test" name="label" v-model="newAssetType.label">
<span class="help-block" v-show="newAssetType.errors.has('label')">
#{{ newAssetType.errors.get('label') }}
</span>
</div>
</div>
<div class="form-group">
{{ Form::label('enabled', 'Enabled?', ['class' => 'col-md-4 control-label']) }}
<div class="col-md-6">
<input type="checkbox" name="enabled" v-model="newAssetType.enabled" >
</div>
</div>
<!-- Submit -->
<div class="form-group">
<div class="col-md-8 col-md-offset-4">
<button class="btn btn-primary" #click="createType" :disabled="newAssetType.busy">
Create Asset Type
</button>
</div>
</div>
<div id="assignProps" v-if="newAssetType.successful">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Add Property
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Add New Property to Asset Type</h4>
</div>
<div class="modal-body">
<assign-asset-prop v-for="property in properties" class="panel panel-info property-item">
<div class="panel-heading">#{{ property.label }}</div>
<div class="panel-body"><strong>Input Type: </strong>#{{ property.input_type }}
<div class="pull-right">
<input type="hidden" name="prop_id" v-bind:value="property.p_id" v-model="assignPropForm.prop_id">
<input type="hidden" name="type_id" v-bind:value="property.p_id" v-model="assignPropForm.type_id">
<button class="btn btn-primary" #click="assignProp" :disabled="assignPropForm.busy">
Add
</button>
</div>
</div>
</assign-asset-prop>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</new-asset-type>
#endsection
Thanks to the helpful comments, I learned that I shouldn't have been using hidden inputs at all. Instead, I simply passed the variables to the function on the click event.
<button class="btn btn-primary" #click="assignProp(type_id, property.p_id)" >
Add
</button>
Then in my component
methods: {
assignProp: function (type_id, property_id) {
var assignPropForm = new SparkForm({
propvalue: property_id,
typevalue: type_id,
});
Spark.post('/asset-properties/add', assignPropForm)
.then(response => {
console.log(response);
})
.catch(response => {
console.log("fail");
});
}
}
You need store variables at local data() dep., and geting it by getters function.

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