How to use Vue.js to template a Modal and reuse it? - javascript

So currently I have a web app that loads a dashboard based on a SQL database and that works just fine, each of these elements have buttons and those buttons are SUPPOSED to spawn a modal with the content of the problem and you can interact with it etc.
Recently I have figured out how to use Vue.js to run a function that grabs this information and populate it on the modal. However, this modal can only be templated ONCE before it wont work again. Ex: I can click on problem 1 and problem 1's information is correct. however, if I click problem 2 after that it doesn't work
new Vue({
delimiters: ['!!!','!!!'],
el: '#problem-modal',
methods: {
close() {
this.$emit('close');
},
},
data: {
items: [],
name: null,
summary: null,
},
mounted: function () {
var self = this;
fetch('./api/problems')
.then(response => {
var response = response.json();
return response;
})
.then(json => {
var data = json.data;
var length = data.length;
for (var i = 0; i<length; i++) {
if (data[i].unique_id == button_id) {
this.name = data[i].problem_name;
this.summary = data[i].summary;
}
}
})
}
})
}
Here is my Script for the vue, assume that the problems load perfectly and this:
<div class="modal fade" id="problem-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">!!! name !!!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
!!! summary !!!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
is the modal. Any idea on how to make the modal element able to be used more than once?
Thanks!

I give you nearest illustration of your question ! I thought items is your problem list . As you mentioned you have to clicked button so that pass your clicked data to call method and grab data from items with that pass clicked data and set vue data . I hope it will be ok .. Look at my example
new Vue({
el: '#problem-modal',
methods: {
show(id) {
let cur = this.items.find(x => x.id == id);
this.name = cur.name;
this.summary = cur.summary;
}
},
data: {
items: [
{
id: 1,
name: "one",
summary: "one summary "
},
{
id: 2,
name: "two",
summary : "two summary"
}
],
name: null,
summary: null,
}
});
button {
width: 100%;
height: 20px;
margin: 10px 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="problem-modal">
<button v-for="item in items" #click="show(item.id)">{{item.id}}</button>
<div class="modal">
<h1>{{name}}</h1>
<pre>{{summary}}</pre>
</div>
</div>

Related

How to pass a parameter to a modal form using Ajax

I have a razor page that displays a list of expenses for the Report selected. I have an "Add Expense" button on the page that brings up a modal. The modal is a partial View of the form. What i need to do is pass the ExpenseId to the modal. I can get the Id from the url like this
#{ var expenseId = Request.Url.Segments[3]; }
the button currently looks like this
<button type="button" data-toggle="modal" data-target="#expenseModal_#expenseId" data-id="#expenseId" class="btn btn-primary" id="addExpenses">
Add Expense
</button>
There are a few things in this that i do not know if i even need them. I was trying different things.
Modal
<!-- MODAL -->
<div class="modal fade" id="expenseModal_#expenseId" tabindex="-1" role="dialog" aria-labelledby="expenseModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="expenseModalLabel"> Expences </h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div> <!-- MODEL HEADER-->
<div class="modal-body">
</div> <!-- MODAL BODY-->
</div>
</div>
Javascript
<script type="text/javascript">
$(document).ready(function () {
$("#addExpenses").click(function () {
$(".modal-body").html('');
$.ajax({
type: 'GET',
url: '#Url.Action("_ExpenseForm", "Admin")',
data: { type: $(this).attr("data-type") },
success: function (response) {
$(".modal-body").html(response);
$("#expenseModal").modal('show');
},
error: function () {
alert("Something went wrong");
}
});
});
});
</script>
The expense Id has to be inserted in the form so that when it is saved it saves it to the correct Expense report.
Controller actions
ExpensesDataAcessLayer objexpense = new ExpensesDataAcessLayer();
public ActionResult ExpenseReports()
{
return View(db.ExpenseReports.ToList());
}
public ActionResult Expenses(int ExpenseId)
{
return View(db.Expenses.Where(x => x.ExpenseId == ExpenseId).ToList());
}
public ActionResult _ExpenseForm()
{
CustomerEntities customerEntities = new CustomerEntities();
List<SelectListItem> categoryItem = new List<SelectListItem>();
ExpensesViewModel casModel = new ExpensesViewModel();
List<ExpenseTypes> expensetypes = customerEntities.ExpenseType.ToList();
expensetypes.ForEach(x =>
{
categoryItem.Add(new SelectListItem { Text = x.CategoryItem, Value = x.ItemCategoryId.ToString() });
});
casModel.ExpenseTypes = categoryItem;
return View(casModel);
}
Thanks for your help!
You can store expenseId into hidden field, like this
<input id="expenseId" name="expenseId" type="hidden" value="#Request.Url.Segments[3]">
Then you can get like this
$("#addExpenses").click(function () {
var expenseId = $("#expenseId").val();
// after code here
Updated
You can get expenseId like this
var expenseId = $(this).attr("data-id")
Then you can assign it to hidden field or anywhere in Model, Like this
<!-adding aditional input into HTML in MODEL-!>
<input id="expenseId" name="expenseId" type="hidden" value="">
<!- Javascript-!>
var expenseId = $(this).attr("data-id")
expenseId.val(expenseId );

Image not loading in nested route vue js

I've created a custom component for my app to select multiple images for product:
<template>
<!-- Image modal -->
<div
class="modal fade"
id="gallery-multi"
tabindex="-1"
role="dialog"
aria-labelledby="galleryLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-lg " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="gallery">Gallery</h5>
<button type="button" class="close" #click="closeModal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<vue-select-image
:dataImages="dataImages"
:is-multiple="true"
#onselectmultipleimage="onSelectMultipleImage"
:h="'90'"
:w="'140'"
></vue-select-image>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" #click="closeModal()">Close</button>
</div>
</div>
</div>
</div>
</template>
<script>
import VueSelectImage from "vue-select-image";
import "vue-select-image/dist/vue-select-image.css";
export default {
name: "selectMultiImg",
data() {
return {
multiID:[],
dataImages: [
{
id: "",
src: "",
alt: ""
}
]
};
},
methods: {
closeModal() {
$("#gallery-multi").modal("hide");
},
onSelectMultipleImage: function(data) {
this.multiID = data.id;
this.$emit('multiImg', this.multiID);
}
},
components: { VueSelectImage },
mounted() {
axios.get("/api/gallery").then(response => {
this.dataImages = response.data.map((obj, index) => {
return {
id: obj.id,
src: obj.thumb,
alt: obj.name
};
});
});
}
};
</script>
I'm using this component in other routes as well (main routes) like:
{
path: "/product-category",
component: require("./components/product/Category.vue")
},
and it runs smoothly in main routes. But I'm having trouble in nested route:
{
path: "/product/create",
component: require("./components/product/Create.vue"),
},
The problem is image doesn't load in nested route.
In the above picture the original path of the image is src="img/thumb_dcb7d855594bb92d2fd83108e8a2620e.jpg" but in highlighted section of the path is http://localhost:3000/product/img/thumb_dcb7d855594bb92d2fd83108e8a2620e.jpg
Which is added by the vue itself (I suppose). Furthermore there is no error in console also.
Can anyone help me figure out what is causing this and its possible solution ?
It not Vue added this URL.
Use absolute path to images.
Example:
src: '/' + obj.thumb

Google Maps autocomplete in Bootstrap modal with Vue.js

I have Boostrap modal with <input>. I have implemented Google autocomplete for it with the following well-known trick:
.pac-container {
z-index: 10000 !important;
}
Now I'm struggling to make autocomplete working inside 2nd layer Boostrap Modal. Unfortunately, the z-index trick doesn't work here.
<div class="modal fade" id="editItemModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div id="editItem" class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
Update Address <b>{{selectedItem.properties.NAME}}</b>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label class="sr-only" for="editItem_ADRESS1"></label>
<input v-model="selectedItem.properties.ADRESS1" type="text" class="form-control" id="editItem_ADRESS1" ref="editItem_ADRESS1" placeholder="{{selectedItem.properties.ADRESS1}}">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<a class="btn btn-success btn-ok" #click="save_item()" data-dismiss="modal">Save</a>
</div>
</div>
</div>
</div>
Then comes the Vue object
const editItem = new Vue({
el: "#editItem",
data: {
items: null,
selectedItem: null,
},
methods: {
save_item() {
this.selectedItem = itemsList.selectedItem;
var ip = location.host;
$.ajax({
type: 'POST',
dataType: 'json',
url: 'http://' + ip + '/updateItem',
data: {
command: "edit_item",
item_id: this.selectedItem.id,
adress1: this.selectedItem.properties.ADRESS1
},
success: function (responseData) {
if (responseData.result === false) {
console.log(responseData.result);
}
else {
console.log("successfully updated");
}
},
error: function (error) {
console.log('error', error);
}
}); // end of ajax
} // end od save_item()
} // end of methods
});
Finally, I was able to figure out what was the issue. It turns out that the DOM object is not created yet by Vue when the Google iniAutocomplete() function sets listeners.
In addition, my <input> didn't run the Google geolocate() function. That's how the <input> looks now:
<div class="form-group">
<label class="sr-only" for="edit-item_ADRESS1"></label>
<input id="edit-item_ADRESS1" v-model="selectedItem.properties.ADRESS1" type="text" class="form-control" onFocus="geolocate('edit-item')">
</div>
The next step was to make a minor change in the geolocate() function. I pass action variable onFocus event and use it to determine what DOM object initiated the call.
if (action == "add-item") {
autocomplete_add_item.setBounds(circle.getBounds());
}
if (action == "edit-item") {
// we need to run iniAutocomplete again after the DOM object was finally created by Vue
initAutocomplete();
autocomplete_edit_item.setBounds(circle.getBounds());
}

UI Grid v3.1.0 column auto width issue detected

I have found many questions about UI Grid autowidth issue. I managed to reproduce one of them and would like to share with you the details on how to reproduce it.
First, I have the default UI Grid inside of a hidden modal (you can find the code snippet at the end of this post).
Steps to reproduce:
Run the code snippet, press "Launch demo modal"; (there is no issues);
Close the modal;
Resize browser window. here it is. Column width is reset to a wrong value.
var app = angular.module('app', ['ui.grid']);
app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
$scope.gridOptions1 = {
enableSorting: true,
columnDefs: [
{ field: 'name' },
{ field: 'gender' },
{ field: 'company', enableSorting: false }
],
onRegisterApi: function( gridApi ) {
$scope.grid1Api = gridApi;
}
};
$scope.gridOptions1.data = [
{ name: 1, gender: 2, company: 3 },
{ name: 1, gender: 2, company: 3 },
{ name: 1, gender: 2, company: 3 },
{ name: 1, gender: 2, company: 3 },
{ name: 1, gender: 2, company: 3 }];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css" rel="stylesheet"/>
<link href="https://rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.css" rel="stylesheet"/>
<script src="https://rawgit.com/HubSpot/tether/master/dist/js/tether.js"></script>
<script src="https://rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-touch.js"></script>
<script src="https://rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.js"></script>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<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">Modal title</h4>
</div>
<div class="modal-body" ng-app="app">
<div ng-controller="MainCtrl">
<div id="grid1" ui-grid="gridOptions1" class="grid"></div></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
Also I would like to share with you an approach of fixing it.
Actually, there are two bugs here.
UI Grid is set to 0 on page resize when modal is hidden;
UI Grid is set to 0 on page load.
The first one is easy to detect and fix if you use uncompressed version of UI Grid:
There reason of both issues is the same. The width of hidden element is zero.
A simple workaround with jQuery will be as follows for the first case:
// Resize the grid on window resize events
function gridResize($event) {
grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
console.log(grid.gridWidth);
console.log(grid.gridHeight);
if(!$($elm).is(':hidden') && grid.gridWidth > 0) { //add such if statement before
grid.refreshCanvas(true); //this is UI Grid code
}
}
The second case is not so simple to fix. Because we need to get the width of Grid container ( in this case modal is the container ).
Container might be inside of a hidden element ( that means jQuery(gridContainer).width() will return zero ).
That is how I came across jQuery.actual plugin (github or demo). I will use it to show you a solution for this specific case:
// Initialize the directive
function init() {
if($($elm).is(':hidden')) { //added
grid.gridWidth = $scope.gridWidth = $($elm).parent().actual('width'); //added
} //added
else { //added
grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm); //this is UI Grid code
} //added
}
As result we will get a UI Grid with proper auto width feature.
Finally, we do not need $Interval workaround from the tutorial with this approach.

Function to append modal

I have 3 modals that all have the same format and are activated by different onclicks (Create Contact, Update Contact, Delete Contact). I am wanting the modal-title and modal-body to change depending on which button was clicked. How would I go about creating a function that appends the modal content depending on which button was clicked? Thank you for your help!
<div id="myModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Confirmation</h4>
</div>
<div class="modal-body">
<p>Contact Created!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
</div>
</div>
</div>
I have written the JavaScript "BootstrapModel" class for the same purpose.
It also depends on jQuery so don't forget to embed jQuery before using this class.
class is :
var BootstrapModal = (function (options) {
var defaults = {
modalId: "#confirmModal",
btnClose: "#btnClose",
title: "Confirm",
content: "Some bootstrap content",
onClose: function () {
},
onSave: function () {
}
};
defaults = options || defaults;
var $modalObj = $(defaults.modalId);
var hideModal = function () {
$modalObj.modal("hide");
};
var showModal = function () {
$modalObj.modal("show");
};
var updateModalTitle = function (title) {
defaults.title = title;
//$($modalObj).find(".modal-title").eq(0).html(title);
$modalObj.find(".modal-title").eq(0).html(title);
};
var updateModalBody = function (content) {
defaults.content = content;
$modalObj.find(".modal-body").eq(0).html(content);
};
return {
getDefaults: function () {
return defaults;
},
hide: function () {
hideModal();
},
show: function () {
showModal();
},
updateTitle: function (title) {
updateModalTitle(title);
return this;
},
updateBody: function (body) {
updateModalBody(body);
return this;
}
}
});
Usage :
var emailModal = new BootstrapModal({modalId: "#confirmModal"});
emailModal.updateTitle("Mail sent successfully").updateBody("<br/>This box will automatically close after 3 seconds.").show();
// Hide the Modal
emailModal.hide();
HTML Structure for the Modal:
<div class="modal fade" id="confirmModal" role="dialog" aria-labelledby="thankyouModal" aria-hidden="true" style="overflow-y: hidden;">
<div class="modal-dialog" style="padding-top: 225px">
<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="thankyouModal">Thank you</h4>
</div>
<div class="modal-body">
Thank you. We'll let you know once we are up.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The way I got around this is by loading the data in from external files. So you'd have your initial declaration of your modal box (just the surrounding div), and then in each file you have the containing code for the rest of the modal, then use a bit of jQuery to fire them off:
HTML (in main file)
<div class="modal" id="modal-results" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
</div>
JQuery
$('#create-contact').click(function(){
e.preventDefault();
$("#modal-results").html('create-contact.html');
$("#modal-results").modal('show');
});

Categories

Resources