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();
}
}
});
Related
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>
I have 2 components:
Vue.component('repo-button', {
props:["check_in_id", "repo_id"],
template: '#repo-button',
methods: {
fetchRepo: function() {
url = window.location.href.split("#")[0] + "/check_ins/" + this.check_in_id + "/repositionings/" + this.repo_id + ".json"
cl(url)
cl(this)
var that;
that = this;
$.ajax({
url: url,
success: function(data) {
cl(data)
that.showRepo();
}
})
},
showRepo: function() {
// what do I put here to display the modal
}
},
data: function() {
var that = this;
return {
}
}
});
Vue.component('repo-modal', {
template: "#repo-modal",
data: function() {
return {
status: 'none'
}
}
});
var repositionings = new Vue({
el: "#repo-vue"
});
...and my view consists of a button and a modal. I'd like the button to call fetchRepo on the repo-button component and display the modal (change its status property from none to block.
<script type="text/x-template" id="repo-button">
<div class='socialCircle-item success'>
<i class='fa fa-comment'
#click="fetchRepo"
:data-check_in='check_in_id'
:data-repo='repo_id'>
</i>
</div>
</script>
<script type="text/x-template" id="repo-modal">
<div v-bind:style="{ display: status }" class="modal" id="vue-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-client_id="<%= #client.id %>">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"></h4>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-danger btn-simple" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</script>
<div id="repo-vue">
<div is="repo-modal"></div>
<div is="repo-button" repo_id="<%= ci.repositioning.id %>" check_in_id="<%= ci.id %>"></div>
</div>
Props down, events up
In Vue.js, the parent-child component relationship can be summarized
as props down, events up. The parent passes data down to the child via
props, and the child sends messages to the parent via events.
In particular, if the state of a component needs to be controlled externally (by a parent or sibling), that state should be passed in as a prop from the parent. Events indicate to the parent that the state should be changed.
Your modal's state is controlled by events in itself and in a sibling component. So the state lives in the parent, and is passed to the modal as a prop. Clicking the modal Close button emits a (custom) hidemodal event; clicking the sibling component's comment icon emits a showmodal event. The parent handles those events by setting its showRepoModal data item accordingly.
Vue.component('repo-button', {
template: '#repo-button',
methods: {
showRepo: function() {
this.$emit('showmodal');
}
}
});
Vue.component('repo-modal', {
template: "#repo-modal",
props: ["show"],
computed: {
status() {
return this.show ? 'block' : 'none'
}
},
methods: {
hideRepo() {
this.$emit('hidemodal');
}
}
});
var repositionings = new Vue({
el: "#repo-vue",
data: {
showRepoModal: false
}
});
.socialCircle-item i {
cursor: pointer;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<template id="repo-button">
<div class='socialCircle-item success'>
<i class='fa fa-comment'
#click="showRepo"
>
</i>
</div>
</template>
<template id="repo-modal">
<div v-bind:style="{ display: status }" class="modal" id="vue-modal" 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"></h4>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button type="button" #click="hideRepo" class="btn btn-danger btn-simple" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</template>
<div id="repo-vue">
<div is="repo-modal" :show="showRepoModal" #hidemodal="showRepoModal = false"></div>
<div is="repo-button" #showmodal="showRepoModal = true"></div>
</div>
I am using a reusable bootstrap modal i.e same modal for edit, delete operations.
When edit or update buttons are clicked same modal will pop up and I need to append appropriate functions to the modal footer buttons according which operation it is.
My footer buttons are like,
<div class="modal-footer">
<button class="btn actionBtn" data-dismiss="modal">
<span id="footer_action_button" class='glyphicon'> </span>
</button>
<button class="btn btn-warning" data-dismiss="modal">
<span class='glyphicon glyphicon-remove'></span> Close
</button>
</div>
When edit button is clicked,
$(document).on('click', '.edit-modal', function() {
$('#footer_action_button').text(" Update");
$('#footer_action_button').addClass('glyphicon-check');
$('#footer_action_button').removeClass('glyphicon-trash');
$('.actionBtn').addClass('btn-success');
.....
......
$('#myModal').modal('show');
$('.actionBtn').click(updateOperation);
});
similarly for delete action too..
here $('.actionBtn').click(updateOperation); would work well normallly.
but here updateOperation is a vueJs function,
methods: {
updateOperation: function () {
.....
.....
},
}
I am unable to call this update operation.
When statically adding #click="updateOperation()", it works fine.
<button class="btn actionBtn" data-dismiss="modal"
#click="updateOperation()">
<span id="footer_action_button" class='glyphicon'> </span>
</button>
I'm not sure to quite understand your question, but here is how I've done it:
I have a Modal component:
Modal.vue:
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" #click="close()">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">
{{ title }}
</h4>
</div>
<div class="modal-body">
<slot></slot>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" #click="close()">Fermer</button>
<button type="button" class="btn btn-primary" #click="save()" :disabled="loading"><i class="fa fa-spin fa-spinner" v-if="loading"></i>Confirmer</button>
</div>
</div>
And:
export default {
props: ['title','save','close','loading']
}
As you can see, I take a save and close method in argument of the Modal component.
Then, when I call the component from another one, I send the methods as parameters:
Parent.vue:
<modal v-show="showModal" title="Ajouter une adresse" :save="saveAddress" :close="hideModal" :loading="savingNewAddress">
My Modal content here
</modal>
export default {
data () {
return {
this.showModal = false;
}
},
methods: {
saveAddress () {
console.log('fired from my parent component');
},
hideModal () {
this.showModal = false;
},
displayModal () {
this.showModal = true;
}
},
components: {
Modal
}
}
I hope this helps!
In my UI Grid here are the Column Defs in my myController.js file:
{ field: 'trans_typ_dsc', headerTooltip: 'Transaction Type Description', displayName: 'Transaction Type Description', cellTemplate: '<div class="wordwrap">{{COL_FIELD}}</div>' },
{ field: 'trans_stat', displayName: 'Transaction Status' },
{ field: 'sub_trans_actn_typ', displayName: 'Sub Transaction Action Type', cellTemplate: '<div class="wordwrap">{{COL_FIELD}}</div>' , visible : false },
{ field: 'case_key', displayName: 'Case Key', visible: true, celltemplate: '<a class="text-center" ng-href="#" ng-click="grid.appScope.setAssociateCaseModal(row)">{{COL_FIELD}}</a>' },
{ field: 'approved_by', displayName: 'Approved By', visible: false }
Here on clicking the case_key link a UI Bootstrap modal should pop up .
How to do that ?
I know in a html file using a button click it is something like :
<h3>Search Transaction</h3>
<div style="float: right; margin-top: -35px"><button type="button" class="btn btn-default" data-toggle="modal" data-target="#recentSearchesModal">Recent Searches</button></div>
</div>
<div class="modal fade" id="recentSearchesModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Recent Searches</h4>
</div>
<div class="modal-body">
<div class="panel panel-default">
<div class="menu_simple" ng-repeat="obj in CaseRecentSearches" style="padding:8px;">
<ul>
<li>
{{obj | placeholderfunc}}
</li>
</ul>
</div>
<!-- /.panel-body -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
But here the click event is my controller.js file then how to get the modal opened ?
You need to modify the field's cellTemplate and then call grid.appScope.openModal(). openModal should live in your main controller under $scope.openModal. Do it like this:
Your template:
var myTemplate = "<a href='#' ng-click='grid.appScope.openModal($event, row)'>{{ row.entity.myFieldName }}</a>";
Use the template in gridOptions.
$scope.gridOptions = {
columnDefs: [{
field: 'myFieldName',
displayName: 'My Field Name',
cellTemplate: myTemplate;
}]
};
Function to call modal:
$scope.openModal = function (e, row) {
//in here, you can access the event object and row object
var myEvent = e;
var myRow = row;
//this is how you open a modal
var modalInstance = $uibModal.open({
templateUrl: '/path/to/modalTemplate.html',
controller: MyModalCtrl,
backdrop: 'static'
//disable the keyboard
//keyboard: false,
resolve {
//pass variables to the MyModalCtrl here
event: function() { return myEvent; },
row: function() { return myRow; }
}
});
//call the modal to open, then decide what to do with the promise
modalInstance.result.then(function() {
//blah blah the user clicked okay
},function(){
//blah blah the user clicked cancel
})
}
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>   My Favorites</button>
<!-- Split button -->
<div class="btn-group">
<button type="button" class="btn secondaryBtn userControls"><span class="glyphicon glyphicon-user"></span>   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