UI Grid v3.1.0 column auto width issue detected - javascript

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.

Related

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

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>

Set focus on a input control contained in a second level bootstrap modal

I'm using Vue.js 2.1.10 and Bootstrap 3.3.7 to show a modal that opens another modal dialog. Each modal dialog is contained in a distinct component. Inside the 1st component, there is a reference to the 2nd component (select-travler).
According to the Bootsrap documentation, I have to set the focus by listening to the event shown.bs.modal. This works great to set the focus on an input control contained in the 1st modal. Problem: this way doesn't work when the modal is above another modal.
The 1st modal component looks like this:
<template>
<div ref="tripEdit" class="modal fade" role="dialog">
<!-- Inbeded component -->
<select-travler ref="selectTravler"></select-travler>
<!-- /Inbeded component -->
<div class="modal-lg modal-dialog">
<div class="modal-content">
<div class="modal-body container form-horizontal">
<div class="form-group">
<label for="travler_name" class="control-label">
Travler's name
</label>
<input id="travler_name" ref="travler_name"
v-model="travler_name"/>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
travler_name: null,
}
},
methods: {
show (operationType) {
$(this.$refs.tripEdit).modal('show');
let that = this;
$(this.$refs.tripEdit).on('shown.bs.modal', function () {
$(that.$refs.travler_name).focus();
});
if (operationType === 'newTravel') {
this.$refs.selectTravler.show();
}
},
},
}
</script>
The 2nd component contains a similar layout with the following show method:
show () {
$(this.$refs.selectTravler).modal('show');
let that = this;
$(this.$refs.selectTravler).on('shown.bs.modal', function () {
$(that.$refs.people_names).focus();
});
},
When the 2nd modal opens, the focus is still on the 1st modal behind the 2nd modal dialog (I can see the caret blinking in travler_name). How can I set the focus on people_names when the 2nd modal is shown?
I think there are really several issues at play here. First, as I mentioned in the comment above, you are not properly adding and removing the shown.bs.modal event handlers.
Second, because your second modal is nested inside the first modal, the shown.bs.modal event will bubble up to the parent modal and it's handler will fire. Initially I thought stopPropagation would be a good way to handle this, but in the end, I simply de-nested the submodal component in the template.
Here is an example of this behavior actually working.
console.clear()
Vue.component("sub-modal", {
template: "#submodal",
methods: {
show() {
$(this.$el).modal("show")
},
onShown(event) {
console.log("submodal onshown")
this.$refs.input.focus()
}
},
mounted() {
$(this.$el).on("shown.bs.modal", this.onShown)
},
beforeDestroy() {
$(this.$el).off("shown.bs.modal", this.onShown)
}
})
Vue.component("modal", {
template: "#modal",
methods: {
show() {
$(this.$refs.modal).modal("show")
},
showSubModal() {
this.$refs.submodal.show()
},
onShown(event) {
console.log("parent")
this.$refs.input.focus()
}
},
mounted() {
$(this.$refs.modal).on("shown.bs.modal", this.onShown)
},
beforeDestroy() {
$(this.$refs.modal).off("shown.bs.modal", this.onShown)
}
})
new Vue({
el: "#app",
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div id="app">
<modal ref="modal"></modal>
<button #click="$refs.modal.show()" class="btn">Show Modal</button>
</div>
<template id="submodal">
<div class="modal fade" tabindex="-1" role="dialog">
<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">Modal title</h4>
</div>
<div class="modal-body">
<input ref="input" type="text" class="form-control">
</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><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</template>
<template id="modal">
<div>
<div ref="modal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" 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">Modal title</h4>
</div>
<div class="modal-body">
Stuff
<input ref="input" type="text" class="form-control">
</div>
<div class="modal-footer">
<button #click="showSubModal" type="button" class="btn btn-primary">Show Sub Modal</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<sub-modal ref="submodal"></sub-modal>
</div>
</template>
Also, for future readers, I got some useful information about how to construct the template for the modal component used above from this answer. Specifically, unless you manually specify a z-index for the modal, the modal that appears last in HTML will have a higher z-index. The implication being the submodal component needs to come second in the template.
I ran into a similar issue. A b-modal forces focus to stay in the modal. You can disable it by adding a no-enforce-focus attribute.
no-enforce-focus Boolean false Disables the enforce focus routine
which maintains focus inside the modal
https://bootstrap-vue.org/docs/components/modal
This means that the element you're trying to focus is not properly referenced.
Trying to console.log(element); the line before focussing people_names. To see if you're getting the right element.
show () {
$(this.$refs.selectTravler).modal('show');
let element = this.$refs.people_names;
$(this.$refs.selectTravler).on('shown.bs.modal', function () {
$(element).focus();
});
},
Have you considered v-show to open and close your modals ?

Use Bootstrap Modal on Fullcalendar js

I have a question, I am having a hard time to figure out a way to use bootstrap modal in fullcalendar. What I am trying to do is when you click on the event on the calendar, the modal will pop-up and provide the full name of the event and summary of the event.
The following is the code I am using to generate the calendar:
<cffunction name="FullCalendar">
<cfscript>
var calendarid = $.getbean('content').loadby(title='Regal Events').getcontentid();
</cfscript>
<cfsavecontent variable="local.str">
<cfoutput>
<div id="UpcomingCal" class="calendarResize">
</div>
<div id="fullCalModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span> <span class="sr-only">close</span></button>
<h4 id="modalTitle" class="modal-title"></h4>
</div>
<div id="modalBody" class="modal-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button class="btn btn-primary"><a id="eventUrl" target="_blank">Event Page</a></button>
</div>
</div>
</div>
</div>
<script>
mura.loader()
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.css",{media:'all'})
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar-custom.css",{media:'all'})
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.print.css",{media:'print'})
.loadjs(
"#$.siteConfig('requirementspath')#/fullcalendar/lib/moment.min.js",
"#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.min.js",
"#$.siteConfig('requirementspath')#/fullcalendar/gcal.js",
function(){
$('##UpcomingCal').fullCalendar({
weekMode: 'variable',
eventSources: [
{
$('#eventUrl'): '#variables.$.siteConfig('requirementspath')#/fullcalendar/proxy.cfc?calendarid=#esapiEncode("javascript",CalendarID)#'
, type: 'POST'
, data: {
method: 'getFullCalendarItems'
, calendarid: '#esapiEncode("javascript",CalendarID)#'
, siteid: '#variables.$.content('siteid')#'
, categoryid: '#esapiEncode('javascript',variables.$.event('categoryid'))#'
, tag: '#esapiEncode('javascript',variables.$.event('tag'))#'
}
<!---, color: '#this.calendarcolors[colorIndex].background#'
, textColor: '#this.calendarcolors[colorIndex].text#'--->
, error: function() {
$('##mura-calendar-error').show();
}
},
]
});
}
)
</script>
</cfoutput>
</cfsavecontent>
<cfreturn local.str />
</cffunction>
As you can see above, I have included the bootstrap modal. However, I am not sure how to add the following code so that when you click on the event, the modal appears:
$(document).ready(function() {
$('#bootstrapModalFullCalendar').fullCalendar({
events: '/hackyjson/cal/',
header: {
left: '',
center: 'prev title next',
right: ''
},
eventClick: function(event, jsEvent, view) {
$('#modalTitle').html(event.title);
$('#modalBody').html(event.description);
$('#eventUrl').attr('href',event.url);
$('#fullCalModal').modal();
}
});
});
Any help would be appreciated
Thanks
Your problem is not is not related to javascript, bootstrap or fullcalendar.
I created a minimal test case to help you out and it works.
You should check coldfusion and mura.loader code.

How to show a modal dialog using bootstrap

Earlier i was using a jquery dialog to show a pop-up message. However I need to use boostarp for my project and I am not able to figure out a way to actually show the pop-up.
The code that i used for my jquery dialog:
showUserWarningMessage: function (title, message, callback, scope, username) {
var $dialog = $("#dialog-move-user-warning");
$dialog.dialog({
resizable: false,
height: 450,
width: 580,
modal: true,
top: 200,
dialogClass: "warning-dialog",
title: title,
position: ["center", 200],
open: function () {
$dialog.find(".btn-default").on("click", function () {
$dialog.dialog("close");
});
$dialog.find(".btn-primary").on("click", function () {
$dialog.dialog("close");
if (callback) {
if (scope) {
callback.call(scope);
} else {
callback();
}
}
});
},
And he code im writing for bootstrap modal:
showAlertMessage: function(options) {
var $dialog = $("#dialog-move-user-warning");
$dialog.modal("show");
}
HTML:
<div class="modal fade" id="dialog-move-user-warning" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="myModalLabel">User Info</h4>
</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>
For some reason its not displaying anything on the screen, though the background gets disabled as though there is an overlay popped, but can see it. i tried changing the defaults set for the class="modal", but it didnt help.
What im i doing wrong, or anything additional needed for the overlay to display?
is there any css that i need to change?
Thanks in advance!
Below are multiple ways opening modal dialog using bootstrap
Method 1: Open modal window using javascript
$("#myModal").modal('show');
Method 2:
<button (click)="deleteStudent(item.student_id)" class='btn btn-danger'>Delete</button>
Method 3:
<button class='btn btn-success' data-toggle="modal" data-target="#myModalMore">Open</button>
Method 4:
<button href="#mypop" class="btn btn-success" data-backdrop="false" data-toggle="modal">Open Modal</button>
<div id="mypop" class="modal fade">
//modal code here
</div>
If you want to show a modal using Bootstrap, why don't you use Bootstrap?
1. Add the modal html to your page.
The modal html you've provided is valid, if you are not certain, you can find the exact code and more examples here: http://getbootstrap.com/javascript/#modals-examples
2. Add a trigger to your page.
Data-target should be equal to your modal ID, which is #dialog-move-user-warning in your case.
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Launch demo modal
</button>
3. Make sure you have bootstrap.js and bootstrap.css included on your website.
The Bootstrap modal relies heavily on bootstrap.js. You don't need everything, what you will find in the JSFiddle below is just enough.
http://jsfiddle.net/fgxmcnd2/3/

Bootstrap 3 Modal with Ember.js, no data in modal

I want to use Bootstrap 3's modal along with Ember.js. So far, I have been unsucessfull. The data modal itself is not appearing, although the screen is doing the fade.
my app.js:
App = Ember.Application.create();
App.ApplicationRoute = Ember.Route.extend({
events: {
showGroups: function() {
this.container.lookup('view:groups').append();
}
}
});
App.GroupsRoute = Ember.Route.extend({
model: function() {
return groups;
}
});
App.GroupsView = Ember.View.extend({
templateName: "groups",
classNames: ["modal", "fade"],
didInsertElement: function() {
this.$().modal('show');
this.$().one("hidden", this._viewDidHide);
},
// modal dismissed by example clicked in X, make sure the modal view is destroyed
_viewDidHide: function() {
if (!this.isDestroyed) {
this.destroy();
}
},
// here we click in close button so _viewDidHide is called
close: function() {
this.$(".close").click();
}
});
var groups = [
{
id: 1,
name: 'Family Reunion',
},
{
id: 2,
name: 'California Trip',
},
{
id: 3,
name: 'Dream Vacations',
},
{
id: 4,
name: 'Fun for Kids',
},
];
My templates:
<script type="text/x-handlebars" data-template-name="application">
<button class="btn actionBtn userControls" {{action showGroups}}><span class="glyphicon glyphicon-heart"></span> &nbsp My Favorites</button>
<!-- Split button -->
<div class="btn-group">
<button type="button" class="btn secondaryBtn userControls"><span class="glyphicon glyphicon-user"></span> &nbsp Hello, <b>User</b></button>
<button type="button" class="btn secondaryBtn dropdown-toggle userControls" data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu secondaryMenu" role="menu">
<li>Account Settings</li>
<li>Logout</li>
</ul>
</div>
</script>
<script type="text/x-handlebars" data-template-name="groups">>
<div class="modal fade" id="favoritesModal">
<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 tertiaryHeading">My Favorite Groups</h4>
</div>
<div class="modal-body">
{{#each model}}
{{render "group" this}}
{{/each}}
</div>
<div class="modal-footer">
<button type="button" class="btn actionBtn">Create New Group</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</script>
<script type="text/x-handlebars" data-template-name="group">
<button class="btn secondaryBtn groupBtn">{{name}}</button>
</script>
How can I make this work? I'm new to Ember, and not sure if I understand how to inject data into a view?
You have two issues that are slowing you down.
First, your 'groups' template is never being inserted into the DOM. this.container.lookup('view:groups').append() does not do what you seem to think it does. The Ember Way (tm) is to use an outlet for rendering nested templates, and modals are really just a special case of nesting. (You can use the View Tree of the Ember inspector to see that the 'groups' template is never inserted.)
I would recommend altering your ApplicationRoute to be this (use actions instead of events, and just transitionTo the 'groups' route):
App.ApplicationRoute = Ember.Route.extend({
actions: {
showGroups: function() {
this.transitionTo('groups');
}
}
});
At this point you should see that the 'groups' template is making it into the DOM, but it's still not being shown. This is due to the second issue, which is that you have a modal inside a modal (yo dawg!). Your GroupsView is creating a new element and setting class names of modal and fade on the new element. Your groups template is being rendered into that element, but the outer div in your groups template has the class names of modal and fade. The outer modal (created by GroupsView) is being "displayed", but since it contains content that is explicitly hidden (due to the modal fade classes) nothing is shown on screen. You could either remove the outer div in your template, or remove the class names from GroupsView, and then display the modal with this.$('#favoritesModal').modal('show').
Here's a working JSBin : http://jsbin.com/ucanam/1311/edit

Categories

Resources