Angularjs - UI Boostrap: Accordion Open and close all - javascript

i have written some code to open and close all tabs of an accordion respectively use a separate 'open' and 'close' button. How ever it requires me to dynamically add a key value pair(a Boolean value) to my json data.
What is the best practice in this situation? should i add the Boolean value as a static json element or is it OK to dynamically add values when their sole purpose is for visual structure and not relevant to actual object data.
HTML/Angular directives
<div id="app" ng-app="demoApp">
<div id="controller" ng-controller="demoAppCtrl">
<uib-accordion close-others="false">
<div class="btn-group form-group">
<button type="button" class="btn btn-warning" ng-click="toggle(true)">Open</button>
<button type="button" class="btn btn-warning" ng-click="toggle(false)">Close</button>
</div>
<uib-accordion-group is-open="hero.state" ng-click="setOpened(false)" ng-repeat="hero in heroes">
<uib-accordion-heading>
{{hero.name}}
</uib-accordion-heading>
{{hero.bio}}
</uib-accordion-group>
</uib-accordion>
</div>
</div>
Javascript/Angular
var app = angular.module('demoApp', ['ngAnimate','ui.bootstrap']);
app.controller('demoAppCtrl', function($scope) {
// This json object contain only one entry as an example
$scope.heroes = [
{'name': 'Captain America', 'team': 'Avengers', 'bio': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vitae metus placerat, condimentum nisl et, accumsan sapien. Quisque molestie magna nulla, id malesuada sem interdum a.'}
];
$scope.addDefaultState = function(val) {
for (var i=0;i<$scope.heroes.length;i++) {
$scope.heroes[i].state = val;
}
}
$scope.addDefaultState(false);
$scope.toggle = function(status) {
$scope.heroes.forEach(function(e) {
e.state = status;
});
}
});
codepen.io - Working example (with corrections)

In my opinion the static json should not contain Boolean state value. It is okay to dynamically add values for visual presentation.
In your code the function addDefaultState is not needed. The is-open="hero.state" will take care of default state cause initially it will not find state and will consider it as false. So you change your code like below it should work too:
var app = angular.module('demoApp', ['ngAnimate','ui.bootstrap']);
app.controller('demoAppCtrl', function($scope) {
// This json object contain only one entry as an example
$scope.heroes = [
{'name': 'Captain America', 'team': 'Avengers', 'bio': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vitae metus placerat, condimentum nisl et, accumsan sapien.'}
];
$scope.toggle = function(status) {
$scope.heroes.forEach(function(e) {
e.state = status;
});
}
});

Related

How can I make html file dynamic with angularjs

I have an html file and a JS file. The JS file contains some data that I want to present in the html file depending on a clicked link from another html file
html file:
<div class="jumbotron mb-5">
{{product.name}}
</div>
<div class="jumbotron mb-5">
{{product.price}}
</div>
<div class="jumbotron mb-5">
{{product.description}}
</div>
js file
var app = angular.module('app', [']);
app.controller('prodCtrl', function ($scope) {
$scope.courses = [
{
id: 1,
name: 'prod 1',
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid ea fugit
tempore error, tenetur adipisci hic voluptas sapiente distinctio,.',
price: 100,
image: 'public/photos/prod1.png'
},
{
id: 2,
name: 'prod 2',
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit.',
price: 30,
image: 'public/photos/prod2.png'
},
];
});
in another html page I have the products listed as links and I want to present them in the html page up there depending on the link I clicked
You would pass the param in the route with ui-router
It sounds like you're asking for dynamic routing. There are a few questions about this on SO, but to point you in the right direction for what you're doing:
You have to declare your routes in the app config like so:
angular.module('myApp', [
'ui.router'
])
.config(function($stateProvider) {
$stateProvider
.state({
name: 'product',
url: '/product/{id}', //{id} or :id will tell it to expect the param
templateUrl: '/products/index.html',
controller: 'ProdCtrl'
});
});
Inside your index.html file, make sure you add:
<div ng-app="myApp">
<ui-view></ui-view>
</div>
(or where you want the content to appear)
And finally, your controller:
.controller('ProdCtrl', function($scope, $stateParams) {
//get id from the url and convert it to an int to match data type in courses id
//may want to consider doing some validation
$scope.productId = parseInt($stateParams.id);
var courses = [
{
id: 1,
name: 'prod 1',
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit.',
price: 100,
image: 'public/photos/prod1.png'
},
{
id: 2,
name: 'prod 2',
description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit.',
price: 30,
image: 'public/photos/prod2.png'
}
];
//find the matching item by id and set it to scope
$scope.product = courses.map(function(item) {
if (item.id === $scope.productId) {
return item;
}
});
});
You should now be able to go to /product/1 and see prod 1
Please note this is untested code, but should get you on the right track. I also renamed a couple things for clarity and be more aligned with common practices (e.g. myApp and ProdCtrl).
If you go through the ui-router documentation, you can also achieve this without using the id in the url and have it pass params in the background. This would mean you can only access that page via links in your app and not deep link them.

TINYMCE Editor External Templates: Uncaught TypeError: Cannot read property 'indexOf' of undefined

I am using TINYMCE Editor Version 4.8.2 (2018-08-09) and trying to add few prebuilt templates in .html in the list. I installed the template plugin in the plugin directory and initiated it in init-tinymce.js as below.
tinymce.init({
/* replace textarea having class .tinymce with tinymce editor */
selector: "textarea",
/* plugin */
plugins: [
"template"
],
/* toolbar */
toolbar: "template",
/* templates */
templates: [
{
title : "Default Template 1",
src : "tinymce-templates/template1.html",
description : "Default Template"
},
{
title : "Default Template 2",
src : "tinymce-templates/template2.html",
description : "Default Template"
}
]
});
Now when I try to open and insert my added templates then I am able to see my both template in the dropdown list but when I cant see the preview. On inspecting, I found this error shared below.
Uncaught TypeError: Cannot read property 'indexOf' of undefined plugin.min.js:1
at S (plugin.min.js:1)
at i.onselect (plugin.min.js:1)
at Vg.c.fire (tinymce.min.js:2)
at i.fire (theme.min.js:1)
at w (plugin.min.js:1)
at plugin.min.js:1
at i.<anonymous> (plugin.min.js:1)
at Vg.c.fire (tinymce.min.js:2)
at i.fire (theme.min.js:1)
at HTMLDivElement.o (theme.min.js:1)
S # plugin.min.js:1
onselect # plugin.min.js:1
Vg.c.fire # tinymce.min.js:2
fire # theme.min.js:1
w # plugin.min.js:1
(anonymous) # plugin.min.js:1
(anonymous) # plugin.min.js:1
Vg.c.fire # tinymce.min.js:2
fire # theme.min.js:1
o # theme.min.js:1
C # tinymce.min.js:2
d
And my template is like something below...
<div class="mceTmpl">
<div class="row">
<div class="box">
<div class="col-lg-12">
<hr>
<h2 class="intro-text text-center">Build a website
<strong>worth visiting</strong>
</h2>
<hr>
<hr class="visible-xs">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
</div>
</div>
</div>
</div>
I believe where you have a src attribute the correct attribute is url. Per the documentation I see this:
This option lets you specify a predefined list of templates to be
inserted by the user into the editable area. It is structured as an
array with each item having a title, description and content/url.

How do I update blog post in Mongoose?

I am building a blog site using CRUD operations. I can create, read and delete but I am having hard time with updating a created post.
Basically I have it where I can click on the "edit" button on an individual entry in home.ejs and into the edit.ejs route where that input fields are populated with current title and content. But what I can not figure out is clicking "Publish" in edit.ejs to update its own post.ejs title and content. When it is done, I want to redirect it back to the main page. Down on the "app.post("/edit/:id")" route, am I supposed to use "PUT" request to update the post?
I am sorry if this is tough to follow. I am not very good at explaining things.
Here's the relevant code:
app.js
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const _ = require("lodash");
const aboutContent = "Hac habitasse platea dictumst vestibulum rhoncus est pellentesque. Dictumst vestibulum rhoncus est pellentesque elit ullamcorper. Non diam phasellus vestibulum lorem sed. Platea dictumst quisque sagittis purus sit. Egestas sed sed risus pretium quam vulputate dignissim suspendisse. Mauris in aliquam sem fringilla. Semper risus in hendrerit gravida rutrum quisque non tellus orci. Amet massa vitae tortor condimentum lacinia quis vel eros. Enim ut tellus elementum sagittis vitae. Mauris ultrices eros in cursus turpis massa tincidunt dui.";
const contactContent = "Scelerisque eleifend donec pretium vulputate sapien. Rhoncus urna neque viverra justo nec ultrices. Arcu dui vivamus arcu felis bibendum. Consectetur adipiscing elit duis tristique. Risus viverra adipiscing at in tellus integer feugiat. Sapien nec sagittis aliquam malesuada bibendum arcu vitae. Consequat interdum varius sit amet mattis. Iaculis nunc sed augue lacus. Interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit. Pulvinar elementum integer enim neque. Ultrices gravida dictum fusce ut placerat orci nulla. Mauris in aliquam sem fringilla ut morbi tincidunt. Tortor posuere ac ut consequat semper viverra nam libero.";
let app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static("public"));
mongoose.connect("mongodb://localhost:27017/blogDB", {
useNewUrlParser: true
});
const postSchema = {
date: String,
title: String,
content: String
}
const Post = mongoose.model("Post", postSchema);
app.get("/", (req, res) => {
Post.find({}, (err, posts) => {
res.render("home", {
posts: posts
});
});
});
app.get("/about", (req, res) => {
res.render("about", {
aboutContent: aboutContent
});
});
app.get("/contact", (req, res) => {
res.render("contact", {
contactContent: contactContent
});
});
app.get("/compose", (req, res) => {
res.render("compose");
});
app.post("/compose", (req, res) => {
const postTitle = req.body.postTitle;
const postBody = req.body.postBody;
let date = new Date();
let postDate = date.toLocaleString('en-US');
const post = new Post({
date: postDate,
title: postTitle,
content: postBody
});
post.save(err => {
if (!err) {
res.redirect("/");
}
});
});
app.get("/edit/:id", (req, res) => {
const requestedId = req.params.id;
console.log(req.body);
Post.findOne({
_id: requestedId
}, (err, post) => {
if (!err) {
res.render("edit", {
title: post.title,
content: post.content
});
}
});
});
app.post("/edit/:id", (req, res) => {
const requestedId = req.params.id;
console.log(req.body);
Post.findOne({
_id: requestedId
}, (err, post) => {
if (!err) {
res.render("edit", {
title: post.title,
content: post.content
});
}
});
});
app.get("/posts/:id", (req, res) => {
const requestedId = req.params.id;
Post.findOne({
_id: requestedId
}, (err, post) => {
if (!err) {
res.render("post", {
title: post.title,
content: post.content
});
}
});
});
app.post("/delete", (req, res) => {
const deletePost = req.body.delete;
Post.findByIdAndDelete(deletePost, (err) => {
if (!err) {
res.redirect("/");
}
});
});
app.listen(3000, function () {
console.log("Server started on port 3000");
});
home.ejs
<%- include("partials/header") -%>
<h1>Home</h1>
<button type="button" class="new-entry btn btn-dark">New Entry</button>
<div class="entries-container">
<% posts.forEach(post => { %>
<div class="blog-entry">
<p class="post-date">Posted on
<%= post.date %>
</p>
<h2>
<%= post.title %>
</h2>
<div class="entry-footer">
<button type="button" class="btn btn-outline-primary">VIEW</button>
<form action="/edit" method="POST">
EDIT</button>
</form>
<form action="/delete" method="POST">
<button type="submit" name="delete" value="<%= post._id %>" class="btn btn-outline-danger">DELETE</button>
</form>
</div>
</div>
<% }) %>
</div>
<%- include("partials/footer") -%>
edit.ejs
<%- include("partials/header") -%>
<h1>Compose</h1>
<form action="/edit" method="PUT">
<div class="form-group">
<label for="postTitle">Title</label>
<input type="text" name="postTitle" class="form-control" id="postTitle" autocomplete="off" value="<%= title %>">
<label for="postBody">Post</label>
<textarea name="postBody" class="form-control" autocomplete="off" rows="8"><%= content %></textarea>
</div>
<button type="submit" name="button" class="btn btn-primary">Publish</button>
</form>
<%- include("partials/footer") -%>
post.ejs
<%- include("partials/header") -%>
<h2 class="post-title"><%= title %></h2>
<p class="post-content"><%= content %></p>
<%- include("partials/footer") -%>
If you want to simply update your existing blog post title and content with sending POST request then you can do it with findOneAndUpdate() as below:
app.post("/edit/:id", (req, res) => {
const requestedId = req.params.id;
console.log(req.body);
Post.findOneAndUpdate({
_id: requestedId // Query Part
},
{
$set: {
title: req.body.title, // Fields which we need to update
content: req.body.content
}
},
{
new: true // option part ( new: true will provide you updated data in response )
},(err, post) => {
if (!err) {
res.render("edit", {
title: post.title,
content: post.content
});
}
});
});

Underscore template can't access data model

I am having difficulty accessing model data with underscore, nothing is appearing on screen and I'm not getting any errors. Any help would be greatly appreciated.
Here is my templating area
<script type='text/template' id='ListContainerView'>
<p> <%= ListItemModel.id %> </p>
<p> <%= ListItemModel.network %> </p>
<p> <%= ListItemModel.created_by_id %> </p>
</script>
Collection
var ListItemCollection = Backbone.Collection.extend({
baseUrl: '/api/get_accounts',
url: '/api/get_accounts',
model: ListItemModel,
total: 0,
// Sample data
TESTDATA: {"status":"ok","posts":[{"id":"1","schedule":"2020-0417 17:00:00","utc_offset":"420","project_id":"1","network":"facebook","network_name":"TestFacebookPage","network_thumb":"https://scontent.xx.fbcdn.net/v/t1.0-9/17634406_1854330461448271_6787736791983791423_n.jpg?oh=e4c3a3573c0fc59359422cfd66a3865a&oe=598721E7","message":"Test Post 1 (just text, approved)","data":[],"customer_approved":"1","manager_approved":"1","rejection_message":"","created_at":"2020-0413 17:41:03","created_by":"admin","created_by_id":"1","created_by_name":"John Admin"},{"id":"2","schedule":"2020-0419 19:00:00","project_id":"1","network":"facebook","network_name":"TestFacebookPage","network_thumb":"https://scontent.xx.fbcdn.net/v/t1.0-9/17634406_1854330461448271_6787736791983791423_n.jpg?oh=e4c3a3573c0fc59359422cfd66a3865a&oe=598721E7","message":"Test Post 2 (text with image, approved) Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.","data":{"pictures":["https://pbs.twimg.com/media/C9T6n0UUwAAOBaU.jpg"],"image_added":"true","picture":"https://pbs.twimg.com/media/C9T6n0UUwAAOBaU.jpg","type":"photo"},"customer_approved":"1","manager_approved":"1","rejection_message":"","rejection_message_manager":"","created_at":"2020-0413 17:42:34","created_by":"admin","created_by_id":"1","created_by_name":"John Admin"},{"id":"3","schedule":"2020-0421 22:00:00","network":"facebook","network_name":"TestFacebookPage","network_thumb":"https://scontent.xx.fbcdn.net/v/t1.0-9/17634406_1854330461448271_6787736791983791423_n.jpg?oh=e4c3a3573c0fc59359422cfd66a3865a&oe=598721E7","message":"Test Post 3 (link, approved) http://www.adultswim.com/videos/rick-and-morty/","data":{"image_added":"true","pictures":["http://i.cdn.turner.com/adultswim/big/img/2015/07/17/Rick%26MortyS02_fbsearchTn.jpg"],"picture":"http://i.cdn.turner.com/adultswim/big/img/2015/07/17/Rick%26MortyS02_fbsearchTn.jpg","link":"http://www.adultswim.com/videos/rick-and-morty/","name":"Watch Rick and Morty on Adult Swim","caption":"www.adultswim.com","description":"Every episode of Rick and Morty is now on AdultSwim.com for free. Rick is a mad scientist who drags his grandson, Morty, on crazy sci-fi adventures. Their escapades often have potentially harmful consequences for their family and the rest of the world. Join Rick and Morty on AdultSwim.com as they trek through alternate dimensions, explore alien planets, and terrorize Jerry, Beth, and Summer.","domain":"www.adultswim.com","type":"link"},"customer_approved":"1","manager_approved":"1","rejection_message":"","created_at":"2020-0413 17:43:29","created_by":"admin","created_by_id":"1","created_by_name":"John Admin"},{"id":"4","schedule":"2020-0424 17:00:00","network":"facebook","network_name":"TestFacebookPage","network_thumb":"https://scontent.xx.fbcdn.net/v/t1.0-9/17634406_1854330461448271_6787736791983791423_n.jpg?oh=e4c3a3573c0fc59359422cfd66a3865a&oe=598721E7","message":"Test Post 4 (text, pending)","data":[],"customer_approved":"0","manager_approved":"1","rejection_message":"","created_at":"2020-0413 17:43:48","created_by":"admin","created_by_id":"1","created_by_name":"John Admin"},{"id":"5","schedule":"2020-0426 19:00:00","network":"facebook","network_name":"TestFacebookPage","network_thumb":"https://scontent.xx.fbcdn.net/v/t1.0-9/17634406_1854330461448271_6787736791983791423_n.jpg?oh=e4c3a3573c0fc59359422cfd66a3865a&oe=598721E7","message":"Test Post 5 (picture, pending)","data":[],"customer_approved":"0","manager_approved":"1","rejection_message":"","created_at":"2020-0413 17:44:03","created_by":"admin","created_by_id":"1","created_by_name":"John Admin"},{"id":"6","schedule":"2020-0428 21:00:00","network":"facebook","network_name":"TestFacebookPage","network_thumb":"https://scontent.xx.fbcdn.net/v/t1.0-9/17634406_1854330461448271_6787736791983791423_n.jpg?oh=e4c3a3573c0fc59359422cfd66a3865a&oe=598721E7","message":"Test Post 6 (link, pending) https://www.reddit.com/","data":{"image_added":"true","pictures":["https://b.thumbs.redditmedia.com/2Hwaff37fC4f37j-3orrbjVAOVBChqbdm_dXeIhjlNw.jpg"],"picture":"https://b.thumbs.redditmedia.com/2Hwaff37fC4f37j-3orrbjVAOVBChqbdm_dXeIhjlNw.jpg","link":"https://www.reddit.com/","name":"reddit: the front page of the internet","caption":"www.reddit.com","description":"reddit: the front page of the internet","domain":"www.reddit.com","type":"link"},"customer_approved":"0","manager_approved":"1","rejection_message":"","created_at":"2020-0413 17:44:19","created_by":"admin","created_by_id":"1","created_by_name":"John Admin"}],"total":"6"},
initialize: function(models, options) {
this.total = this.TESTDATA.total;
this.reset(this.TESTDATA.posts);
}
})
Views...
var ListContainerView = SOCIView.extend({
template: _.template($('#ListContainerView').text()),
className: 'ListContainerView'
})
var SOCIView = Backbone.View.extend({
render: function() {
if (typeof this.beforeRender === 'function') {
this.beforeRender();
}
var modelData = { };
if (this.model && this.model instanceof Backbone.Model) {
modelData = this.model.toJSON();
}
if (typeof this.template === 'function') {
this.$el.html(this.template(modelData));
}
if (typeof this.afterRender === 'function') {
this.afterRender();
}
return this;
}
})
and script inside HTML...
<script type="text/javascript">
$(document).ready(function() {
// Instantiate and render Backbone view
$('.home_body').append( new ListContainerView({
collection: new ListItemCollection(),
}).render().el)
});
</script>
The toJSON method on a Backbone model gives you a simple copy of the model attributes. In your case, this:
modelData = this.model.toJSON();
should give you an object that looks like this:
{
id: 1,
schedule: "2020-0417 17:00:00",
utc_offset: "420",
...
}
Notice that there is no ListItemModel anywhere in that object. That object would be suitable for a template that looks like this:
<p> <%= id %> </p>
<p> <%= network %> </p>
<p> <%= created_by_id %> </p>
If you really wanted the ListItemModel prefixes in the template then you'd want to say:
this.template({ ListItemModel: modelData })
when calling the template function.
Alternatively you could compile the template using the {variable: 'ListItemModel'} option to _.template and leave the template and this.template call alone. So your view would have:
template: _.template($('#ListContainerView').html(), { variable: 'ListItemModel'),
and the rest wouldn't change.
Where you define your template for the ListContainerView, I think using .text() (instead of .html()) might be causing your problem. Instead try
template: _.template($('#ListContainerView').html())
and see if it works.
Jquery's .text() ignores html markup like <span> or <strong> tags (etc), so it may be removing your templating tags <% ... %> as well, giving you just a few spaces.

Ionic app - controller $http

I am building a app in ionic, i am trying to get external restful api data into the view via a controller, but there seems to be something wrong with my controller because nothing is being pulled in?
my code is:
angular.module('starter', ['ionic'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
StatusBar.styleDefault();
}
});
})
.controller('myCtrl', function($scope, $http) {
$http.get('http://jsonplaceholder.typicode.com/posts').then(function(results){
$scope.posts = results.data.posts;
}, function(err) {
console.error('ERR', err);
// err.status will contain the status code
})
});
<ion-content class="has-subheader" ng-controller="myCtrl">
<ion-list>
<ion-item ng-repeat='item in posts' class="item-thumbnail-left item-text-wrap">
<img src="http://placehold.it/100x100" alt="photo">
<h2>{{post.title}}</h2>
<h4>Place</h4>
<p style="font-size:12px; line-height:16px;">Quisque quis sem a velit placerat vehicula quis nec felis. Mauris posuere, nisl vitae condimentum luctus, tellus enim blandit orci, quis efficitur nibh libero eget dui. Aliquam fermentum velit quis sem molestie.</p>
</ion-item>
</ion-list>
</ion-content>
Any help would be appreciated.
Solution to this:
$http.get('http://jsonplaceholder.typicode.com/posts')
.success(function(results){
$scope.posts = results.posts;
console.log($scope.posts);
});
You were using data but there isn't data in the results. Look at the console, and you should see objects now.
Working codepen
you have made 2 mistakes in your code:
First: once you define 'item' in ng-repeat you should use it to bind your object key "title":
ng-repeat='item in posts'
'item' is now holding your JSON keys.
<h2>{{item.title}}</h2>
Second: reviewing jsonplaceholder JSON you are calling through this url, http://jsonplaceholder.typicode.com/posts, title key is under results.data
, so you should define posts like this:
$scope.posts = results.data
For more help: I've taken the code you provided and made it working on a plunk, check it on the following url:
http://embed.plnkr.co/Gp1U3y/preview
Please contact me for more help. Thanks

Categories

Resources