Getting a meteor modal to be dynamic - meteor

I'm working w/ a modal template (maybe I shouldn't be?). On screen, I have a list of products. When a user clicks on a product, I want the modal to open w/ details of that given product.
Right now, what I'm trying to do is update the subscription of the modal. However, the OnCreate() and OnRender() are not firing when the modal opens. Right now the rendered, OnRender, created, and onCreated of the modal all fire when the parent template (the product list) is first opened. I need it to happen when a product is clicked and the modal is shown.
Am I attacking this wrong? Or do I just need to position my subscription somewhere else in the modal?
(adding code - very simple)
<template name="parent">
...
<div class="row form-row">
<div class="col-sm-12 text-right">
<a class="btn btn-outline" type="button" id="remove">Remove</a>
</div>
</div>
{{> productEditModal}}
</template>
<template name="productEditModal">
<div class="modal inmodal" id="productEditModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content animated bounceInRight">
<div class="modal-header">
...
Template.parent.events({
...
"click #aEditProduct": function (e) {
e.preventDefault();
Session.set("productId", this._id);
$('#productEditModal').modal('toggle');
$('#productEditModal').modal('show');
Template.productEditModal.onRendered(function() {
var self = this;
self.autorun(function() {
self.subscribe("products", Session.get("bid"), function() {
var bProduct = BoardProducts.findOne(Session.get("productId")); // some reactive operation
// do fun stuff with thing
});
});
});

ok, here is how I would approach this, assuming you did meteor add peppelg:bootstrap-3-modal
parent template: loop over products and display preview
<template name="parent">
{{#each products}}
{{name}}
{{pic}}
etc...
<a class="btn show-details" type="button">show details</a>
{{/each}}
</template>
create a details modal
<template name="productDetailsModal">
<div class="modal" id="productDetailsModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Details for product {{name}}
...
parent template helper to return products cursor:
Template.parent.helpers({
products() {
return Products.find();
},
})
the event to show details modal for every product
Template.parent.events({
'click .show-details'() {
Modal.show('productDetailsModal', this);
},
})
I wrote this off the top of my head and did not test it. Let me know if it works for you.

Related

How can I route my messenger and messages in Meteor?

Im creating a an instant messenger app and im having a little trouble routing it. So, once you go into the app. There is a list of available users. You can click on a user and start chatting. The issue I have is once I click send, the console show an Uncaught TypeError: Cannot read property 'value' of undefined. Im not sure what im doing wrong here. Also I need help show the chat messages sent above. As if you can see the recent and previous messages. Here are my codes. Any examples and helps would be great.
HTML
minstant
<body>
</body>
<!-- this is the main template used by iron:router to build the page -->
<template name="ApplicationLayout">
{{> yield "header"}}
<div class="container">
{{> yield "main"}}
</div>
</template>
<!-- top level template for the nav bar -->
<template name="navbar">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">
Minstant!
</a>
</div>
<div class="nav navbar-nav">
{{> loginButtons}}
</div>
</div>
</nav>
</template>
<!-- Top level template for the lobby page -->
<template name="lobby_page">
{{> available_user_list}}
</template>
<!-- display a list of users -->
<template name="available_user_list">
<h2>Choose someone to chat with:</h2>
<div class="row">
{{#each users}}
{{> available_user}}
{{/each}}
</div>
</template>
<!-- display an individual user -->
<template name="available_user">
<div class="col-md-2">
<div class="user_avatar">
{{#if isMyUser _id}}
<div class="user_avatar">{{getUsername _id}} (YOU)
<br/>
<img src="/{{profile.avatar}}" class="avatar_img">
</div>
{{else}}
<a href="/chat/{{_id}}">
{{getUsername _id}}
<br/>
<img src="/{{profile.avatar}}" class="avatar_img">
</a>
{{/if}}
</div>
</div>
</template>
<!-- Top level template for the chat page -->
<template name="chat_page">
<h2>Type in the box below to send a message!</h2>
<div class="row">
<div class="col-md-12">
<div class="well well-lg">
{{#each recentMessages}}
{{> message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form class="new-message">
<input class="input" type="text" name="chat" placeholder="type a message here...">
<button class="btn btn-default">Send</button>
</form>
</div>
</div>
</template>
<!-- simple template that displays a message -->
<template name="message">
<div class = "container">
<div class = "row">
<div class = "username">{{username}}
<img src="/{{profile.avatar}}" class="avatar_img">
</div>
<div class = "message-text"> said: {{messageText}}</div>
</div>
</div>
</template>
Here is my JS
Messages = new Mongo.Collection("messages");
if (Meteor.isClient) {
Meteor.subscribe("messages");
Meteor.subscribe("userStatus");
// set up the main template the the router will use to build pages
Router.configure({
layoutTemplate: 'ApplicationLayout'
});
// specify the top level route, the page users see when they arrive at the site
Router.route('/', function () {
console.log("rendering root /");
this.render("navbar", {to:"header"});
this.render("lobby_page", {to:"main"});
});
// specify a route that allows the current user to chat to another users
Router.route('/chat/:_id', function () {
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
///
// helper functions
///
Template.available_user_list.helpers({
users:function(){
return Meteor.users.find();
}
})
Template.available_user.helpers({
getUsername:function(userId){
user = Meteor.users.findOne({_id:userId});
return user.profile.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
Template.chat_page.helpers({
recentMessages: function () {
return Messages.find({}, {sort: {createdAt: 1}});
return Meteor.users.find();
},
});
Template.chat_page.events({
// this event fires when the user sends a message on the chat page
'submit .new-message':function(event){
event.preventDefault();
var text= event.target.text.value;
// stop the form from triggering a page reload
event.target.text.value = "";
// see if we can find a chat object in the database
// to which we'll add the message
Meteor.call("SendMessage", text);
},
});
};
Meteor.methods({
sendMessage: function (messageText) {
if (! Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Messages.insert({
messageText: messageText,
createdAt: new Date(),
username: Meteor.user().username
});
}
});
// start up script that creates some users for testing
// users have the username 'user1#test.com' .. 'user8#test.com'
// and the password test123
if (Meteor.isServer) {
Meteor.startup(function () {
if (!Meteor.users.findOne()){
for (var i=1;i<9;i++){
var email = "user"+i+"#test.com";
var username = "user"+i;
var avatar = "ava"+i+".png"
console.log("creating a user with password 'test123' and username/ email: "+email);
Meteor.users.insert({profile:{username:username, avatar:avatar}, emails: [{address:email}],services:{ password:{"bcrypt" : "$2a$10$I3erQ084OiyILTv8ybtQ4ON6wusgPbMZ6.P33zzSDei.BbDL.Q4EO"}}});
}
}
},
),
Meteor.publish("messages", function () {
return Messages.find();
});
Meteor.publish("userStatus", function() {
return Meteor.users.find({ "status.online": true });
});
};
The error is with your form submit code. In the console you can see the error is in Template.chat_page.events.submit .new-message on line 73. That will take you right to the error code:
'submit .new-message':function(event){
event.preventDefault();
var text = event.target.text.value;
// stop the form from triggering a page reload
event.target.text.value = "";
}
event.target.text.value doesn't exist. event.target does, but there is no field for text. There is textContent, and you can access the children of the target (which in this case is the form). Put in a console.log(event); and figure out what you are trying to access within the javascript console and then use that to determine what your code should look like. This might work for you:
'submit .new-message':function(event){
event.preventDefault();
var text = event.target.elements.chat.value;
// stop the form from triggering a page reload
event.target.text.value = "";
}
event.target.elements.chat.value comes from the name field of the <input>.

Asp.net MVC 5 Ajax call modal dialog

I am new to asp.net MVC 5, I wonder how to use Ajax to call the modal with partial view? i had tried some code but the modal doesn't show up. Any body help?
Here is my code:
View
<script>
#Scripts.Render("~/bundles/jqueryval")
// Create
$(".modalCreate").click(function (e) {
e.preventDefault();
$.ajax({
cache: false,
type: "GET",
url: '#Url.Action("Create","Category")',
success: function () {
$(this).attr('data-target', '#createCat');
$(this).attr('data-toggle', 'modal');
// Attach listener to .modal-close-btn's so that when the button is pressed the modal dialog disappears
$('body').on('click', '.modal-close-btn', function () {
$('#createCat').modal('hide');
});
//clear modal cache, so that new content can be loaded
$('#createCat').on('hidden.bs.modal', function () {
$(this).removeData('bs.modal');
});
$('#CancelModal').on('click', function () {
return false;
});
// Init JQuery Validation for view
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
},
error: function (xhr, ajaxOptions, thrownError) {
displayAjaxError(thrownError);
}
});
});
</script>
<p>
#Html.ActionLink("Create Category ", "Create", "Category",
null, new { #class = "modalCreate btn btn-success" })
</p>
<div id="createCat" class="modal fade"
tabindex="-1" role="dialog">
<div class="modal-content">
</div>
</div>
This is my controller:
public ActionResult Create()
{
return PartialView("_Create");
}
// POST: /Category/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CategoryCreateVM productcategory)
{
if (ModelState.IsValid)
{
ProductCategory cat = Mapper.Map<CategoryCreateVM, ProductCategory>(productcategory);
db.ProductCategories.Add(cat);
db.SaveChanges();
TempData["Message"] = "New Category added sucessfully.";
ViewBag.Message = "New Category added sucessfully.";
return RedirectToAction("Index");
}
return PartialView(productcategory);
}
and partial view:
<div class="modal-dialog">
<div class="modal-body">
<div class="modal-content">
#using (Html.BeginForm("Create", "Category", FormMethod.Post))
{
}
</div>
</div>
</div>
I using the boostrap default theme to do. I try to debug in browser inspection it doesnt show any error. But I can sure is it able to find my partial view but the modal never show up. I hope that anyone can help me check my code.
if I understand well this is the way:
1- add your Modal Template in "<script>" part of Views->Shared->_Layout whith specific id for each part of modal to use it every where you want, for example:
<!-- Modal start-->
<div class="modal fade" id="Modalid" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close"></button>
<h4 class="modal-title" id="ModalLabelid">Modal title</h4>
</div>
<div class="modal-body" id="ModalBodyid"></div>
</div>
</div>
</div>
<!--Modal End-->
2- then add code below in any view that you want use modal :
<script>
function functionname() {
$("#Modalid").modal();
$("#ModalLabelid").html("YourTitle");
$("#ModalBodyid").load("url of partial view or anything that you want show in modal body");
}
</script>
now if you want load body of modal from some partialview , write the url in .load() method :
$("#ModalBodyid").load("/Controller/Action/");
and if your action should get parameter, add the name of parameter exactly as in action entire :
$("#ModalBodyid").load("/Controller/Action/" + NameOfParameterinAction);
finally to use your script you should call functionname() every where you need from any View :)

Meteor Bootstrap 3 Form does not Submit

I'm working with meteor#1.1.10 and twbs:bootstrap#3.3.5
I can get a modal window to spawn, close, and register a button has been clicked. I cannot get it to read any information from a form though. It just closes. I included a console message and it never shows up to either the browser or the command prompt.
Is there a way to do this without including another package? I've included my modal HTML template and Javascript. I'm hoping it's just something missed in the code.
Below is the HTML:
<template name="emodal">
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Spends Email Details</h4>
</div>
<div class="modal-body">
<form class="emailspends">
<label for="input">Recipient:</label>
<input type="text" name="emailto" required>
<label for="input">Character Name:</label>
<input type="text" name="charname" required>
<input type="submit" id="sendemail" class="email" value="Email Spends" data-dismiss="modal">
</form>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
</template>
Below is the Javascript:
Template.emodal.events({
"submit .emailspends": function (event) {
console.log(Meteor.user().emails[0].address);
// Prevent default browser form submit
event.preventDefault();
// Get value from form element
//var emailto = event.target.emailto.value;
var emailto = event.target.emailto.value;
var charname = event.target.charname.value;
var title = "Experience spends for " + charname;
Meteor.call('sendEmail', emailto,
'zbottorff#uwalumni.com', title,
'Yup, modal testies.');
// Clear form
event.target.emailto.value = "";
event.target.charname.value = "";
}
});
Update: Realized I should include this, but I did make sure I could get a submit-able template without it being in a modal window. Now I want to turn it into a modal and it's not submitting.
Bah! I found it just after I posted this.
I had too many parts to my submit button. I removed the "Class" and "id" parts, changed my Javascript to look for a 'submit form' event instead. Voala! Got the bugger to work.

Ui-bootstrap-modal with ui-bootstrap-tpls-0.13 and bootstrap 3.3.2, angular 1.3.14 not working

As mentioned in the title, the modal does not show up.
The content of the form is loaded via formly and the content of the template seems to load, but it only shows the modal very thin, with the overlay but not the content.
I have a main controller in which I have:
$scope.add = function(){
$modal.open({
templateUrl: 'app/js/templates/popupAddCarForm.html',
controller: 'FormsController',
controllerAs: 'vm',
backdrop: 'static',
resolve: {
formData: function(){
return {
fields: getFormFields(),
model: {}
}
}
}
});
};
My html is like so:
<script type="text/ng-template" id="popupAddCarForm">
<div class="modal">
<div class="modal-dialog">
<div class="modal-header">
<h3 class="modal-title">Adauga masina</h3>
</div>
<div class="modal-body">
<form name="vm.addCarForm">
<formly-form model="vm.formData.model" fields="vm.formData.fields">
</formly-form>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-default" type="submit" >Adauga</button>
</div>
</div>
</div>
And my form controller like so:
davidintercar.controller('FormsController',
function($modalInstance, formData) {
var vm = this;
//debugger;
vm.formData = formData;
vm.originalFields = angular.copy(vm.formData.fields);
}
);
The result is like so:
LATER EDIT:
In order to rid ourselfes of other doubts, here is the code from the demo:
app.controller('ModalInstanceCtrl', function ($modalInstance, formData) {
var vm = this;
debugger;
// function assignment
vm.ok = ok;
vm.cancel = cancel;
// variable assignment
vm.formData = formData;
vm.originalFields = angular.copy(vm.formData.fields);
// function definition
function ok() {
$modalInstance.close(vm.formData.model);
}
function cancel() {
$modalInstance.dismiss('cancel');
};
});
Link: angular-formly.com/#/example/integrations/ui-bootstrap-modal
LATER, LATER EDIT:
Plunker: http://plnkr.co/edit/8wgL4t2oXsFFeLBKGGW8?p=preview
Folder Structure:
--app
----js
------controller
------services
------templates
------view
----app.js
intex.html
My popupAddCarForm.html is in the templates directory, but as you see in the plunker, it does not render my loaded content, even in the same directory although a separate template file.
The modal template don't need to have the modal and modal-dialog layer - they will be generated by bootstrap.
<script type="text/ng-template" id="popupAddCarForm.html">
<div class="modal-header">test
<h3 class="modal-title">Adauga masina</h3>
</div>
<div class="modal-body">
<form name="vm.addCarForm">
<formly-form model="vm.formData.model" fields="vm.formData.fields">
</formly-form>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-default" type="submit" >Adauga</button>
</div>
</script>

Iron:Router url parameter to modify nested layout

I'm really struggling with this one. If you want to view what I have bludgeoned together, it is all in a repo on GitHub called instructor-oracle. What I would like to do is have the landing page be the layout at ./wbs. Then I would like the search to route to ./wbs/:_wbsCode and populate the sidebar with the appropriate record. I am thinking the router needs to be structured something like...
Router.configure({
layoutTemplate: 'layout'
});
Router.map(function () {
this.route('wbs', {
path: '/wbs'
}, function () {
this.render('wbs-detail', {
path: '/wbs/:_wbsAbbrev',
to: 'wbs-detail',
data: function () {
theOne = Wbs.findOne({abbrev: this.params._wbsAbbrev});
console.log(theOne.abbrev);
return theOne;
}
});
});
...and this would be paried with templates like...
<template name="layout">
<header class="container-fluid">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="{{pathFor 'wbs'}}">Instructor Oracle</a>
</div>
<div class="collapse navbar-collapse" id="bs-navbar-collapse">
<form class="navbar-form navbar-left" role="search" id="wbsSearchForm">
<div class="form-group">
<input
class="form-control typeahead"
name="wbsSearch"
id="wbsSearch"
type="text"
placeholder="Search"
autocomplete="on"
spellcheck="off"
autofocus="true"
/>
</div>
<button type="submit" class="btn btn-default">Find</button>
</form>
</div>
</nav>
</header>
<main class="container-fluid">
{{> yield}}
</main>
</template>
<template name="wbs">
<div class="col-sm-3" id="wbsCol">
{{> yield 'wbs-detail'}}
</div>
<div class="col-sm-9" id="timesheetCol">
<iframe src="http://iframeurl.html" id="timesheetFrame"></iframe>
</div>
{{#contentFor 'wbs-detail'}}
<h1>{{abbrev}} <small>{{code}}</small></h1>
{{/contentFor}}
</template>
...and an event handler for the form like this...
Template.layout.events({
// catch submit event for wbs form
'submit': function (event, template) {
// prevent default behavior and stop bubbling
event.preventDefault();
event.stopPropagation();
// store dom element in variable
var inputElement = template.find('input#wbsSearch');
// access value in form and extract abbreviation if found
var abbrev = Wbs.findOne({abbrev: (inputElement.value).toUpperCase()}).abbrev;
// clear input
inputElement.value = "";
// go to the page
Router.go('wbs-edit', {_wbsAbbrev: abbrev});
}
});
I have been trying to sort through this on the iron:router documentation, but right now I am all kinds of lost (obviously). Still, I need this to work to avoid reloads on the main layout template so the iframe does not reload while the sidebar can change along with the matching url so links to specific sidebar content can be bookmarked and shared.
Thank you in advance for your assistance. If I eventually sort all of this out, I am more than happy to contribute to the iron:router documentation so it makes sense for the next pea-brained idiot like myself who happens to need to sort this out.

Resources