Why is this template now showing up? - javascript

I have a problem with showing a template on my Meteor.js app. It's website_list. For some reason it doesn't show, maybe you can help me out?
I'm trying to show the website list from the websites MongoDB collection.
HTML Code:
<!-- master layout template -->
<template name="ApplicationLayout">
{{> yield "navbar"}}
{{> yield "main"}}
</template>
<!-- / master layout template -->
<!-- WELCOME -->
<template name="welcome">
<div class="container">
<div class="jumbotron">
<h1>Welcome to Site Ace, {{username}}!</h1>
Enter
</div>
</div>
</template>
<!-- / WELCOME-->
<!-- NAVBAR - you will be putting the login functions here -->
<template name="navbar">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">
Site Ace
</a>
</div>
<ul class="nav navbar-nav login">
<li>
{{> loginButtons}}
</li>
</ul>
</div>
</nav>
</template>
<template name="websites">
<div class="container">
{{> website_form}}
{{> website_list}}
</div>
</template>
<!-- / NAVBAR -->
<!-- WEBSITE FORM -->
<template name="website_form">
{{#if currentUser}}
<a class="btn btn-default js-toggle-website-form" href="#">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add a Website
</a>
{{/if}}
<div id="website_form" class="hidden_div">
<form class="js-save-website-form">
<div class="form-group">
<label for="url">Site address</label>
<input type="text" class="form-control" id="url" placeholder="http://blablabla.org">
</div>
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control" id="title" placeholder="Mysite">
</div>
<div class="form-group">
<label for="description">Description</label>
<input type="text" class="form-control" id="description" placeholder="I found this site really useful for ...">
</div>
<button type="submit" class="btn btn-default js-">Submit</button>
</form>
</div>
</template>
<!-- / WEBSITE FORM -->
<!-- WEBSITE LIST -->
<template name="website_list">
<ol>
{{#each websites}}
{{>website_item}}
{{/each}}
</ol>
</template>
<!-- / WEBSITE LIST -->
<!-- WEBSITE ITEM -->
<template name="website_item">
<li>
{{title}}
<p>
{{description}}
</p>
<p>
<a href="/details/{{_id}}" class="btn btn-info">
Details
</a>
<a href="#" class="btn btn-success js-upvote">
<span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>
</a>
<a href="#" class="btn btn-danger js-downvote">
<span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>
</a>
</p>
<!-- you will be putting your up and down vote buttons in here! -->
</li>
</template>
<!-- / WEBSITE ITEM -->
JS Code:
// SECURITY
Websites = new Mongo.Collection("websites");
// set up security on Websites collection
Websites.allow({
// we need to be able to update websites for ratings.
update:function(userId, doc){
console.log("Testing security on website update");
if (Meteor.user()){// they are logged in
return true;
} else {// user not logged in - do not let them update (rate) the website
return false;
}
},
insert:function(userId, doc){
console.log("Testing security on website insert");
if (Meteor.user()){ // they are logged in
if (userId != doc.createdBy){ // the user is messing around
return false;
}
else{ // the user is logged in, the website has the correct user id
return true;
}
}
else{ // user not logged in
return false;
}
},
remove:function(userId, doc){
return true;
}
})
// / SECURITY
if (Meteor.isClient) {
/////
// ROUTERS
/////
// GLOBAL LAYOUT
Router.configure({
layoutTemplate: 'ApplicationLayout'
});
// ROUTES
Router.route('/', function() {
this.render('welcome', { // welcome is the template to render
to:"main" // main is the template to render welcome INTO
});
});
Router.route('/websites', function() {
this.render('navbar', {
to:"navbar"
});
this.render('websites', {
to:"main"
});
});
Router.route('/websites/:_id', function () {
this.render('navbar', {
to:"navbar"
});
this.render('image', {
to:"main",
data:function(){
return Websites.findOne({_id:this.params._id});
}
});
});
/////
// STARTUP (Creating Websites)
/////
if (Meteor.isServer) {
// start up function that creates entries in the Websites databases.
Meteor.startup(function () {
// code to run on server at startup
if (!Websites.findOne()){
console.log("No websites yet. Creating starter data.");
Websites.insert({
title:"Goldsmiths Computing Department",
url:"http://www.gold.ac.uk/computing/",
description:"This is where this course was developed.",
createdOn:new Date()
});
Websites.insert({
title:"University of London",
url:"http://www.londoninternational.ac.uk/courses/undergraduate/goldsmiths/bsc-creative-computing-bsc-diploma-work-entry-route",
description:"University of London International Programme.",
createdOn:new Date()
});
Websites.insert({
title:"Coursera",
url:"http://www.coursera.org",
description:"Universal access to the world’s best education.",
createdOn:new Date()
});
Websites.insert({
title:"Google",
url:"http://www.google.com",
description:"Popular search engine.",
createdOn:new Date()
});
}
});
}

You forgot to implement a helper function for your website_list template, which returns documents of your Websites collection.
For example:
Template.website_list.helpers({
websites: function() {
return Websites.find();
}
});
Here's a MeteorPad.

Related

How to add a 'Sort By' dropdown to sort a list in Vuejs?

I've got a pretty straight forward setup.
Trying to display a list of users with a search box at the top (for actively filtering the search results).
If I use just that the page works and displays fine.
I'm trying to add in an additional dropdown to pick an attribute to sort by (and hopefully add in another dropdown to indicate ascending/descending once I get the first dropdown working).
My current code (with a non-working version of the sort) looks like this:
<div id="app">
<section class="mb-3">
<div class="container">
<h2>Person Search</h2>
<h3>
<small class="text-muted">Filter people based on the name, location or job</small>
</h3>
<h3>
<small class="text-muted">
Examples: “Jane Doe”, “ABC Building”, or “Math”
</small>
</h3>
<input type="text" class="form-control" v-model="search_term" placeholder="Begin typing to filter by name, location or job...">
<!-- THIS WOULD CAUSE THE LIST TO FILTER ALPHABETICALLY BY SELECTED ATTRIBUTE -->
<select id="sortFilterSelect" name="sort_filter" v-model="sort_filter">
<option value="">Sort By...</option>
<option value="first_name">First Name</option>
<option value="last_name">Last Name</option>
</select>
</div>
</section>
<section>
<div class="container">
<h3>People List : ([[ people_count ]] People)</h3>
<!-- I ADDED 'sortedPeople' HERE - WHICH BROKE IT -->
<div v-for="person in filteredPeople | sortedPeople">
<div class="card mb-4" :class="person.has_summative_past_due ? 'alert-warning' : ''">
<div class="card-body row" >
<div class="col">
<h4 class="card-title" v-bind:person='person.full_name'><a v-bind:href="'{% url 'commonground:index' %}' + 'users/' + person.id">[[ person.full_name ]]</a></h4>
<p v-if="person.active_summative" class="card-text">
Active Summative Due Date: [[ person.active_summative.due_date ]]
<span v-show="!person.active_summative.past_due" v-bind:past_due='person.active_summative.past_due' class="badge badge-success">[[ person.active_summative.due_date_status ]]</span>
<span v-show="person.active_summative.past_due" class="badge badge-danger">[[ person.active_summative.due_date_status ]]</span>
<ul class="list-group list-group-flush">
<li class="list-group-item justify-content-between align-items-center" v-for="summary in person.summative_evaluations_summary">
<span class="badge badge-secondary badge-pill">[[summary.evaluation_type__count]]</span> [[ summary.evaluation_type__name ]]
</li>
</ul>
</p>
<p v-if="!person.active_summative" class="card-text">
No Active Unlocked Summatives
</p>
<a v-if="person.active_summative" :href="person.active_summative.absolute_url" class="btn btn-primary"><i class="far fa-edit"></i> View / Edit Active Summative</a>
</div>
<div class="col-auto float-right text-right">
<p class="h5">
[[ person.base_location ]]
<div v-if="person.multiple_locations" class="small text-muted"><i class="fal fa-info-circle"></i> User has multiple locations</div>
</p>
<p class="h5">
[[ person.assignment_job ]]
<div v-if="person.multiple_jobs" class="small text-muted"> <i class="fal fa-info-circle"></i> User has multiple jobs</div>
</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- END OF VUE -->
</div>
The actual Vue code looks like this:
<script>
const app = new Vue({
delimiters: ['[[', ']]'],
el: '#app',
data: {
people: [],
people_count: 0,
search_term: "",
sort_filter: "",
},
computed: {
filteredPeople:function()
{
var search = this.search_term.toLowerCase();
return this.people.filter(function(person){
return Object.values(person).some( val => String(val).toLowerCase().includes(search))
})
},
sortedPeople:function()
{
var sort_filter = this.sort_filter.toLowerCase();
console.log('triggered')
return this.people.filter(function(person){
return Object.values(person).some( val => String(val).toLowerCase().includes(sort_filter))
})
},
},
async created () {
var response = await fetch("{% url 'user-list' %}");
this.people = await response.json();
this.people_count = await this.people.length
}
})
</script>
Fairly new to Vue, but I am building this to learn. All help is appreciated!
Check out the simple sample I made: Link
filteredPeople() {
return this.people.filter(
(person) =>
person.firstname
.toLowerCase()
.includes(this.search.toLowerCase().trim()) ||
person.lastname
.toLowerCase()
.includes(this.search.toLowerCase().trim())
);
},
sortedPeople() {
return this.filteredPeople.sort((a, b) =>
a[this.sortby].localeCompare(b[this.sortby])
);
},
Added asc/dec order: Link
sortedPeople() {
return this.filteredPeople.sort((a, b) =>
(this.sort == 'asc') ? a[this.sortby].localeCompare(b[this.sortby]) : b[this.sortby].localeCompare(a[this.sortby])
);
},

Issues rendering handlebars to HTML

When I render my handlebars template in html, it looks like it's essentially skipping filling in the "handle bars" portion. I'm essentially printing messages with a title and content, and I'm using a "!each" helper to display all of my messages. I originally thought it was because it was because it was escaping the html around it, so I tried using a triple handle bar {{{ on each part however using the each helper with the triple stash gave me an error. Am I possibly using the handlebars incorrectly?
the typescript I used to render the HTML and my handlebars template is below:
public static refreshData(data: any) {
$("#indexMain").html(Handlebars.templates['main.hbs'](data));
//helper function for upvote button
Handlebars.registerHelper('getUButton', function (id) {
id = Handlebars.escapeExpression(id);
return new Handlebars.SafeString(
"<button type='button' class='btn btn-default up-button' id='u" + id + "'>Upvote</button>"
);
});
//helper function for downvote button
Handlebars.registerHelper("getDButton", function (id) {
id = Handlebars.escapeExpression(id);
return new Handlebars.SafeString(
"<button type='button' class='btn btn-default down-button' id='d" + id + "'>DownVote</button>"
);
});
// Grab the template script
var theTemplateScript = $("#main-template").html();
// Compile the template
var theTemplate = Handlebars.compile(theTemplateScript);
//get messages from server and add them to the context
// This is the default context, which is passed to the template
var context = {
messages: data
}
console.log("context:")
console.log(context);
// Pass data to the template
var theCompiledHtml = theTemplate(context);
console.log(theCompiledHtml);
// Add the compiled html to the page
$("#messages-placeholder").html(theTemplate(context));
//add all click handlers
//get all buttons with id starting with u and set the click listerer
$(".up-button").click((event) => {
var id = $(event.target).attr("id").substring(1);
main.upvote(id)
});
//get all buttons with id starting with d and set the click listerer
$(".down-button").click((event) => {
var id = $(event.target).attr("id").substring(1);
main.downvote(id)
});
}
<script id="main-template" type="text/x-handlebars-template">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Current Messages</h3>
</div>
<div class="panel-body">
<div class="list-group" id="message-list">
<!-- for each message, create a post for it with title, content, upvote count, and upvote button -->
{{#each messages}}
<li class="list-group-item">
<span class="badge">Vote Count: {{likeCount}}</span>
<h4 class="list-group-item-heading">{{title}}</h4>
<p class="list-group-item-text">{{content}}</p>
<div class="btn-group btn-group-xs" role="group" aria-label="upvote">
{{getUButton id}}
</div>
<div class="btn-group btn-group-xs" role="group" aria-label="downvote">
{{getDButton id}}
</div>
</li>
{{/each}}
</div>
</div>
</div>
</script>
<div id="messages-placeholder"></div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Post New Message</h3>
</div>
<div class="input-group">
<span class="input-group-addon">Title</span>
<input id="newTitle" type="text" class="form-control" placeholder="Title" aria-describedby="newTitle">
</div>
<div class="input-group">
<span class="input-group-addon">Message</span>
<input id="newMessage" type="text" class="form-control" placeholder="Message" aria-describedby="newMessage">
</div>
<div class="btn-group" role="group" aria-label="create">
<button type="button" class="btn btn-default" id="postNewMessage">Post Message</button>
</div>
<span class="label label-danger" id="incompleteAcc"></span>
</div>
Okay, then it is likely the data provided to your template is not in the correct form. Here's a working snippet (with non-essentials stripped out). The data passed to your refreshData template must be an array. Make sure it isn't an object containing an array.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js"></script>
</head>
<body>
<script>
let refreshData = (data) => {
// Grab the template script
var theTemplateScript = $("#main-template").html();
// Compile the template
var theTemplate = Handlebars.compile(theTemplateScript);
//get messages from server and add them to the context
// This is the default context, which is passed to the template
var context = {
messages: data
};
console.log("context:", context);
// Add the compiled html to the page
$("#messages-placeholder").html(theTemplate(context));
}
$(() => {
var data = [
{ likeCount: 3, title: 'My Title', content: 'Some content'},
{ likeCount: 0, title: 'My 2nd Title', content: 'Some other content'}
];
refreshData(data);
})
</script>
<script id="main-template" type="text/x-handlebars-template">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Current Messages</h3>
</div>
<div class="panel-body">
<div class="list-group" id="message-list">
<!-- for each message, create a post for it with title, content, upvote count, and upvote button -->
{{#each messages}}
<li class="list-group-item">
<span class="badge">Vote Count: {{likeCount}}</span>
<h4 class="list-group-item-heading">{{title}}</h4>
<p class="list-group-item-text">{{content}}</p>
</li>
{{/each}}
</div>
</div>
</div>
</script>
<div id="messages-placeholder"></div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Post New Message</h3>
</div>
<div class="input-group">
<span class="input-group-addon">Title</span>
<input id="newTitle" type="text" class="form-control" placeholder="Title" aria-describedby="newTitle">
</div>
<div class="input-group">
<span class="input-group-addon">Message</span>
<input id="newMessage" type="text" class="form-control" placeholder="Message" aria-describedby="newMessage">
</div>
<div class="btn-group" role="group" aria-label="create">
<button type="button" class="btn btn-default" id="postNewMessage">Post Message</button>
</div>
<span class="label label-danger" id="incompleteAcc"></span>
</div>
</body>
</html>
When I am faced with issues like this, I eliminate different things until I either get clarity or something I removed fixes the problem. Now I have isolated where the problem lies. In your situation, the issue is likely the data being passed so verify that. Then try stripping out your helpers to see if they are causing issues.

AngularJS - Change view based on user preferences

I am building an email app. It consists of an option to change the default settings. When it is clicked, the following partial view is loaded.
In this view, when the Save changes button is clicked, the values chosen by the user are saved in $localStorage using ngStorage like so:
savePreferenceService.js
(function() {
'use strict';
var savePreferenceService = function ($localStorage) {
this.setPreferences = function (selectedLang, converse, selectedNumber, selectedNumberContact, reply, signature) {
$localStorage.selectedLang = selectedLang;
$localStorage.converse = converse;
$localStorage.selectedNumber = selectedNumber;
$localStorage.selectedNumberContact = selectedNumberContact;
$localStorage.reply = reply;
$localStorage.signature = signature;
console.log($localStorage.selectedLang);
console.log($localStorage.converse);
console.log($localStorage.selectedNumber);
console.log($localStorage.selectedNumberContact);
console.log($localStorage.reply);
console.log($localStorage.signature);
}
};
angular.module('iisEmail')
.service ('savePreferenceService', ['$localStorage', savePreferenceService]);
}());
I have the following questions:
1) Is there a way to store values entered by the user (e.g. selectedLang, converse, selectedNumber) in a JSON file. I have no database.
2) If the user only changes a few preferences (e.g. language preference and number of conversations per page preference), all other preferences (e.g. number of contacts per page and reply) return a value of undefined. Is there a way to return the default values for the preferences that were not changed by the user?. Here is the JSON file that contains the dropdown menu options (e.g. data.languages contains all the languages the user can choose from) and default preferences, data.userPreferences.
settings.json
{
"data": {
"languages": [
"Afrikaans",
"Albanian",
"Arabic",
"Armenian",
"Basque",
"Bengali",
"Catalan",
"Cambodian",
"Chinese (Mandarin)",
"German",
"Greek",
"Gujarati",
"Hebrew",
"Icelandic",
"Maori",
"Marathi",
"Mongolian",
"Serbian",
"Slovak",
"Slovenian",
"Spanish",
"Swahili",
"Swedish",
"Tamil",
"Tatar",
"Telugu"
],
"undoSend": [
5,
10,
20,
30
],
"conversations": [
10,
20,
30,
40,
50,
60,
70,
80,
90,
100
],
"contacts": [
20,
40,
60,
80,
100,
120,
130,
140,
180,
200
],
"userPreferences": {
"selectedLang": "Telugu",
"converse": false,
"selectedNumber": 10,
"selectedNumberContact": 20,
"reply": false,
"signature": "--"
}
}
}
3) My final goal - In the settings page, if the user selects 20 conversations per page, then the next time Inbox is clicked I want to show only 20 emails. Right now, 50 emails are being displayed like so (top-right - It says 1-50 of 277):
Does anyone have ideas regarding these questions?
UPDATE - Question 1
Looks like there is no way to store user entered data in a JSON file, so I am using localStorage to save it on the client-side.
UPDATE - Question 3
Here is a solution for question 3. I bound $scope.conversation property to conversation in the view. The value of $scope.conversation is set to the number selected by the user. This number is saved in localStorage.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Gmail App</title>
<style>
body {
margin: 10px;
padding: 50px;
}
</style>
<link rel="stylesheet" href="Content/css/bootstrap.min.css">
<link rel="stylesheet" href="Content/css/bootstrap-theme.min.css">
<script src="Vendor/jquery-1.11.3.min.js"></script>
<script src="Vendor/bootstrap.min.js"></script>
<script src="Vendor/angular.min.js"></script>
<script src="Vendor/angular-ui-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular-route.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ngStorage/0.3.6/ngStorage.min.js"></script>
</head>
<body data-ng-app="iisEmail">
<div class="container" data-ng-controller="mainController">
<div class="row">
<div class="col-sm-3 col-md-2">
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-toggle="dropdown">
Email <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li>Mail</li>
<li>Contacts</li>
<li data-ng-click="loadView('settings')">Settings</li>
</ul>
</div>
</div>
<div class="col-sm-9 col-md-10">
<!-- split button -->
<div class="btn-group">
<button type="button" class="btn btn-default">
<div class="checkbox" style="margin: 0;">
<label>
<input type="checkbox"
data-ng-click="selectAllEmail()"
data-ng-model="checkAllEmail">
</label>
</div>
</button>
</div>
<button type="button" class="btn btn-default" data-toggle="tooltip" title="Refresh">
   <span class="glyphicon glyphicon-refresh"></span>   
</button>
<!-- Single button -->
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
More <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li>Mark all as read</li>
<li class="divider"></li>
<li class="text-center"><small class="text-muted">Select messages to see more actions</small></li>
</ul>
</div>
<div class="pull-right" data-ng-controller = "settingsController">
<span class="text-muted"><b>1</b>–<b data-ng-bind = "conversation" data-ng-cloak>{{conversation}}</b> of <b>277</b></span>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-default">
<span class="glyphicon glyphicon-chevron-left"></span>
</button>
<button type="button" class="btn btn-default">
<span class="glyphicon glyphicon-chevron-right"></span>
</button>
</div>
</div>
</div>
</div>
<hr/>
<div class="row">
<div class="col-sm-3 col-md-2">
COMPOSE
<hr/>
<ul class="nav nav-pills nav-stacked">
<li class="" data-ng-repeat="item in leftMenu">
<span class="badge pull-right"> {{item.emailCount}}</span> {{item.name}}
</li>
<!--<li>Starred</li>
<li>Important</li>
<li>Sent Mail</li>
<li>-->
</ul>
</div>
<div class="col-sm-9 col-md-10">
<!-- Nav tabs -->
<ul class="nav nav-tabs">
<li class="active"><a href="#home" data-toggle="tab"><span class="glyphicon glyphicon-inbox">
</span>Primary</a></li>
<li><a href="#profile" data-toggle="tab"><span class="glyphicon glyphicon-user"></span>
Social</a></li>
<li><a href="#messages" data-toggle="tab"><span class="glyphicon glyphicon-tags"></span>
Promotions</a></li>
<li><a href="#settings" data-toggle="tab"><span class="glyphicon glyphicon-plus no-margin">
</span></a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div ui-view></div>
</div>
</div>
</div>
</div>
<script src="app/main.js"></script>
<!--Services-->
<script src="app/services/commonApiService.js"></script>
<script src="app/services/savePreferenceService.js"></script>
<script src="app/services/fetchDataService.js"></script>
<script src="app/controllers/mainController.js"></script>
<script src="app/controllers/settingsController.js"></script>
<script src="app/controllers/emailViewController.js"></script>
</body>
</html>
savePreferenceService.js
(function() {
'use strict';
var savePreferenceService = function ($localStorage) {
this.setPreferences = function (selectedLang, converse, selectedNumber, selectedNumberContact, reply, signature) {
$localStorage.selectedLang = selectedLang;
$localStorage.converse = converse;
$localStorage.selectedNumber = selectedNumber;
$localStorage.selectedNumberContact = selectedNumberContact;
$localStorage.reply = reply;
$localStorage.signature = signature;
};
};
angular.module('iisEmail')
.service ('savePreferenceService', ['$localStorage', savePreferenceService]);
}());
settingsController.js
(function() {
'use strict';
var settingController = function (fetchDataService, $scope, savePreferenceService, $localStorage) {
$scope.url = 'app/mock/settings.json';
$scope.save = {};
fetchDataService.getContent($scope.url)
.then(function(response){
$scope.contacts = response.data.contacts;
$scope.languages = response.data.languages;
$scope.conversations = response.data.conversations;
$scope.undoSend = response.data.undoSend;
$scope.save = response.data.userPreferences;
});
$scope.setPreference = function () {
savePreferenceService.setPreferences($scope.save.selectedLang, $scope.save.converse, $scope.save.selectedNumber, $scope.save.selectedNumberContact, $scope.save.reply, $scope.save.signature);
};
$scope.conversation = $localStorage.selectedNumber;
};
angular.module('iisEmail')
.controller ('settingsController',
['fetchDataService', '$scope', 'savePreferenceService', '$localStorage', settingController]);
}());

Bootstrap modal not firing following partial ajax load

I'm using Bootstrap with the latest version of jQuery and am having an issue displaying a modal following a partial update of the page via Ajax.
The modal fires ok multiple times before the UpdateRegister function runs after 60 seconds, after that I receive a "0x800a01b6 - JavaScript runtime error: Object doesn't support property or method 'modal'" when I click on the button to open the modal again.
The button that fires the modal ('#cmdAdd') is outside the Div updated by the Ajax call.
The javascript is as below:
$(function() {
// Display Add Visitor modal
$("#cmdAdd").on("click", function () {
var url = "/Visitor/Add/";
$.get(url, function (data) {
$("#myModal").html(data);
$('#myModal').modal('show');
});
});
// Update register every 60 seconds
setInterval(function () {
UpdateRegister();
}, 60000);
});
function UpdateRegister() {
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth() + 1;
var year = currentDate.getFullYear();
var thisDate = month + "/" + day + "/" + year;
var url = "/Visitor/RegisterList?date=" + thisDate + "&filter=current";
$.get(url, function (data) {
$("#RegisterList").html(data);
});
}
HTML is as follows:
<div class="row">
<div class="col-lg-12">
<h2>#Model.Date.DayOfWeek #Model.Date.ToLongDateString()</h2><br />
<div class="btn-group pull-right">
<button type="button" class="btn btn-danger" id="cmdEmergency">Emergency</button>
<button type="button" class="btn btn-default" id="cmdAdd">Add Visitor</button>
<button type="button" class="btn btn-default" id="cmdAddBulk">Add Bulk Visitors</button>
</div>
<ul class="nav nav-tabs">
<li class="active">Current Register <span class="label label-success" id="CountIn">#Model.VisitorsIn</span></li>
<li>Visitors Expected <span class="label label-success">#Model.VisitorsExpected</span></li>
<li>All Visitors <span class="label label-success" id="CountTotal">#Model.TotalVisitors</span></li>
</ul>
<div class="tab-content">
<!-- Visitors currently in the building -->
<div class="tab-pane active" id="register">
<br /><br />
<div class="row">
<div class="col-lg-12">
<div id="RegisterList">
#Html.Action("RegisterList", new { date = Model.Date, filter="current" })
</div>
</div>
</div>
</div>
<!-- Expected visitors not yet arrived -->
<div class="tab-pane" id="expected">
<br /><br />
<div class="row">
<div class="col-lg-12">
<div id="ExpectedList">
#Html.Action("RegisterList", new { date = Model.Date, filter="expected" })
</div>
</div>
</div>
</div>
<!-- All visitors for the day -->
<div class="tab-pane" id="all">
<br /><br />
<div class="row">
<div class="col-lg-12">
<div id="AllList">
#Html.Action("RegisterList", new { date = Model.Date, filter="all" })
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="myModal">
<!-- Modal content goes here -->
</div><!-- /.modal -->
How can I ensure that the modal still works after the update?
I know it sounds trivial but are you possibly missing a reference to bootstrap.js within the AJAX Html? Adding a reference worked for me when I faced the same error.
I think your #myModal just disappear when #RegisterList is set the data. You should go to check about it.

Why is extending an extended view not working in ember.js?

I am trying to create a modal view and have a base class that all modals need and then extending it for more specific functionality.
PlanSource.Modal = Ember.View.extend({
isShowing: false,
hide: function() {
this.set("isShowing", false);
},
close: function() {
this.set("isShowing", false);
},
show: function() {
this.set("isShowing", true);
}
});
PlanSource.AddJobModal = PlanSource.Modal.extend({
templateName: "modals/add_job",
createJob: function() {
var container = $("#new-job-name"),
name = container.val();
if (!name || name == "") return;
var job = PlanSource.Job.createRecord({
"name": name
});
job.save();
container.val("");
this.send("hide");
}
});
I render it with
{{view PlanSource.AddJobModal}}
And have the view template
<a class="button button-green" {{action show target=view}}>+ Add Job</a>
{{#if view.isShowing}}
<div class="modal-wrapper">
<div class="overlay"></div>
<div class="dialog box box-border">
<div class="header">
<p class="title">Enter a job name.</p>
</div>
<div class="body">
<p>Enter a name for your new job.</p>
<input type="text" id="new-job-name" placeholder="Job name">
</div>
<div class="footer">
<div class="buttons">
<a class="button button-blue" {{action createJob target=view}} >Create</a>
<a class="button" {{action close target=view}}>No</a>
</div>
</div>
</div>
</div>
{{/if}}
The problem is that when I click the button on the modal dialog, it gives me an "action createJob" can not be found. Am I extending the objects incorrectly because it works if I put the createJob in the base Modal class.
Fixed
There was an issue somewhere else in my code. The name got copied and so it was redefining it and making the method not exist.

Categories