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

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

Related

Vuejs 3 - Problem with data function inside a component

I have a list of projects which I get from an api. They get forwarded one by one to this component:
<template>
<button id="project-button" #contextmenu="handler($event)" class="btn btn-outline-secondary mt-1 ms-1" data-bs-toggle="collapse" :data-bs-target="`#${project.Name + project.ID}`">{{project.Name}}</button>
<div :id="`${project.Name + project.ID}`" class="collapse">
<button #click="setProjectId" id="add-object-button" class="btn btn-outline-secondary mt-1 ms-1" data-bs-toggle="modal" data-bs-target="#createObject">
<b>Add Data Object</b>
<i id="plus-icon" class="fas fa-plus"></i>
</button>
<DataObjects :dataObjects="dataobjects"/>
</div>
<CreateObjectModal #add-object="addObject" :projectId="projectId"/>
</template>
<script>
import DataObjects from './DataObjects'
import CreateObjectModal from './CreateObjectModal'
export default {
name: 'Project',
data() {
return {
dataobjects: [],
projectId: 0,
}
},
props: {
project: Object,
},
components: {
DataObjects,
CreateObjectModal
},
methods: {
setProjectId() {
console.log(this.project.ID)
this.projectId = this.project.ID
console.log(this.projectId)
},
async addObject(objectName) {
console.log(objectName)
console.log("After adding object: " + this.projectId)
console.log("Event arrived")
},
Inside the data function I have an object which has the attribute projectId. When I click on the Add Data Object button a modal opens where the user can type in the name of the data object. The modal opens through the data-bs-toggle and data-bs-target attributes. Now in my click event for this button I can get the individual id of a project depending on which button I click. But the problem here is that I will need the specific id of a project inside my addObject function. The addObject function gets called when I click 'Ok' in my modal after the user types in a name. The logs show clearly that if I click on a button the different id gets set correctly but when I click 'Ok' from the modal and the AddObject function gets called then the id remains 1 which is the first id of the projects
I dont know if I am complicating things but I tried to send the id to my modal component which didnt work. The idea was to send it back to the addObject function via $emit. I am kinda stuck with this problem and hope someone can help me. Here is the Modal Component:
<template>
<div>
<div class="modal fade" id="createObject" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">New Data Object</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-floating mb-3">
<input v-model="objectName" class="form-control" id="input">
<label for="input">Object Name:</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<Button data-bs-dismiss="modal" #click="createObject" :text="'Save'"/>
<p>{{projectId}}</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Button from './Button'
export default {
name: 'CreateObjectModal',
data() {
return {
objectName: '',
}
},
props:{
projectId: Number
},
methods: {
createObject() {
this.$emit('add-object', this.objectName)
}
},
components: {
Button
},
emits: ['add-object']
}
</script>

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 ?

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.

bootstrap modal not showing

We are currently stuck using bootstrap 2.3.2, and are looking to replace our current dialogs with bootstrap's modals.
I've located all the views where modals need to be instantiated and attempted 2 ways to call them without success.
With JS:
Html:
<a title='New Group' class='btn btn-fancy' id="btn-new-group" data-bind="visible: Value() == 'CanCreateNewGroup', click: corp.page.CreateGroupDialog.show">New Group<i class="fa fa-fw fa-lg fa-users"></i></a>
JS:
define([
'app-utils',
'jquery',
'bootstrap'
], function (utils) {
var CreateGroupDialog = function () {
};
CreateGroupDialog.prototype = $.extend(true, CreateGroupDialog.prototype, {
show: function (model) {
var dialog = $('#testing-bootstrap').modal({
toggle: true,
show: true,
keyboard: true
});
}
});
return CreateGroupDialog;
});
Without JS:
Html:
<a data-target="#testing-bootstrap" data-toggle="modal" class="btn btn-simple show_tooltip" title="Create Group"><i class="fa fa-fw fa-plus-circle"></i><span>Create Group</span></a>
The reason why I have to come here is that I get NO console errors, NO clue. The JS in my example is being hit, bootstrap is included and I've stepped through bootstrap code and it is loading my modal's html, but it is not coming up on the screen in EITHER way, with no console errors.
Actual modal markup (from bootstrap's example)
<div id="testing-bootstrap" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<button class="btn btn-primary">Save changes</button>
</div>
</div>
Thanks, everyone.
I'm not totally sure how the binding is working in your example - it appears to use the Knockout data-bind attribute, but the rest is jQuery. I'm guessing that your CreateGroupDialog is not being correctly bound to the modal HTML - especially since you are using require.js. If the HTML without JS does not work either, there could be something else wrong, but I would modify your constructor code to bind to your <a> that should trigger the modal.
var CreateGroupDialog = function () {
$( 'a[title="Create Group"]' ).click( $.proxy( this.show, this ) );
};
Then instantiate it:
var modal = new CreateGroupDialog;
The suspected html in the description area of this question was part of an HTML partial which was being called in an area of the application that was not going to be visible then.
If you are using html partials then look into their visibility before doubting the bootstrap modals. That was my problem.

Modal error in ember.js

I'm trying to get a modal to work with my ember application based on the example in this fiddle: http://jsfiddle.net/marciojunior/tK3rX/
However, the modal doesn't open and I am getting this error in my console:
Uncaught Error: Nothing handled the action 'showModal'.
Can anybody spot why? Here's my ModalView:
App.ModalView = Ember.View.extend({
templateName: "modal",
title: "",
content: "",
classNames: ["modal", "fade", "hide"],
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();
}
});
And my subjectRoute which is supposed to handle the showModal event:
App.SubjectRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('subject', params.subject_id);
}
events: {
showModal: function() {
App.ModalView.create({ title: "Edit Subject", content: "My content" }).append();
}
}
});
This is my Subject template from within which I want to be able to open the modal (This is just to test if I can get it working, eventually the modal will be called from the edit button):
<script type = "text/x-handlebars" id = "subject">
{{#if deleteMode}}
<div class="confirm-box">
<h4>Really?</h4>
<button {{action "confirmDelete"}}> yes </button>
<button {{action "cancelDelete"}}> no </button>
</div>
{{/if}}
<h2>{{name}}</h2>
<button {{action "edit"}}>Edit</button>
<button {{action "delete"}}>Delete</button>
{{outlet}}
<a {{action showModal}} href="#">Open modal</a>
</script>
And my Modal View:
<script type="text/x-handlebars" data-template-name="modal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>{{view.title}}</h3>
</div>
<div class="modal-body">
<p>{{view.content}}</p>
</div>
<div class="modal-footer">
<a {{action close target="view"}} href="#" class="btn">Close</a>
Save changes
</div>
</script>
Thanks.
I updated the markup to reflect bootstrap v3.x and removed the hide value from the classNames array of ModalView.
http://emberjs.jsbin.com/IZavuVUM/2#subject
http://emberjs.jsbin.com/IZavuVUM/2/edit
hbs
<script type="text/x-handlebars" data-template-name="modal">
<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">{{view.title}}</h4>
</div>
<div class="modal-body">
<p>{{view.content}}</p>
</div>
<div class="modal-footer">
<a {{action close target="view"}} href="#" class="btn btn-default">Close</a>
Save changes
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</script>
js
App = Ember.Application.create();
App.Router.map(function() {
this.route("subject");
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
App.ModalView = Ember.View.extend({
templateName: "modal",
title: "",
content: "",
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();
}
});
App.SubjectRoute = Ember.Route.extend({
model: function(params) {
return [];//this.store.find('subject', params.subject_id);
},
actions: {
showModal: function() {
App.ModalView.create({ title: "Edit Subject", content: "My content" }).append();
}
}
});

Categories

Resources