Pass multiple params handlebars each block - javascript

So I'm trying to render two form information within a view I can get the one forms information to render however I can't get the second form to render the necessary information.
Here is what I have so far.
<tbody>
{{#each poemRegistrations}}
<tr>
<td>{{schoolName}}</td>
<td>{{competitionResults.winnersName}}</td>
<td>{{poem1AuthorName}}</td>
<td>{{poem1Title}}</td>
<td>{{poem1Url}}</td>
<td>{{poem2AuthorName}}</td>
<td>{{poem2Title}}</td>
<td>{{poem2Url}}</td>
<td>{{poem3AuthorName}}</td>
<td>{{poem3Title}}</td>
<td>{{poem3Url}}</td>
<td>
<div class="btn-group">
<a href="/dashboard/users/forms/poem-registrations/{{_id}}">
<button class="btn">Show</button>
</a>
<a href="/dashboard/users/forms/poem-registrations/edit/{{_id}}">
<button class="btn">Edit</button>
</a>
<a href="/dashboard/users/forms/poem-registrations/delete/{{_id}}">
<button class="btn user-btn-danger">Delete</button>
</a>
</div>
</td>
</tr>
{{/each}}
router.get('/dashboard/all-poems', ensureAuthenticated, (req, res) => {
PoemRegistrations.find({}, function(err, poemRegistrations, competitionResults) {
res.render('dashboard/all-poems.hbs', {
pageTitle: 'All Poems',
poemRegistrations: poemRegistrations,
competitionResults: competitionResults
});
});
});
The PoemRegistration form information is rendering however I just want to get the winners name from another form.
How would I go about doing this?

You may use the {{#root}} helper in Handlebars V2.0.0 :{{#root.competitionResults.winnersName}}
Or you could also include ../ segments to change the context to the root : {{../competitionResults.winnersName}}
Hope this helps.

Related

Pre-populate current value of WTForms field in order to edit it

I have a form inside a modal that I use to edit a review on an item (a perfume). A perfume can have multiple reviews, and the reviews live in an array of nested documents, each one with its own _id.
I'm editing each particular review (in case an user wants to edit their review on the perfume once it's been submitted) by submitting the EditReviewForm to this edit_review route:
#reviews.route("/review", methods=["GET", "POST"])
#login_required
def edit_review():
form = EditReviewForm()
review_id = request.form.get("review_id")
perfume_id = request.form.get("perfume_id")
if form.validate_on_submit():
mongo.db.perfumes.update(
{"_id": ObjectId(perfume_id), <I edit my review here> })
return redirect(url_for("perfumes.perfume", perfume_id=perfume_id))
return redirect(url_for("perfumes.perfume", perfume_id=perfume_id))
And this route redirects to my perfume route, which shows the perfume and all the reviews it contains.
This is the perfume route:
#perfumes.route("/perfume/<perfume_id>", methods=["GET"])
def perfume(perfume_id):
current_perfume = mongo.db.perfumes.find_one({"_id": ObjectId(perfume_id)})
add_review_form = AddReviewForm()
edit_review_form = EditReviewForm()
cur = mongo.db.perfumes.aggregate(etc)
edit_review_form.review.data = current_perfume['reviews'][0]['review_content']
return render_template(
"pages/perfume.html",
title="Perfumes",
cursor=cur,
perfume=current_perfume,
add_review_form=add_review_form,
edit_review_form=edit_review_form
)
My issue
To find a way to get the review _id in that process and have it in my perfume route, so I can pre-populate my EditReviewForm with the current value. Otherwise the form looks empty to the user editing their review.
By hardcoding an index (index [0] in this case):
edit_review_form.review.data = current_perfume['reviews'][0]['review_content']
I am indeed displaying current values, but of course the same value for all reviews, as the reviews are in a loop in the template, and I need to get the value each review_id has.
Is there a way to do this, before I give up with the idea of allowing users to edit their reviews? :D
Please do let me know if my question is clear or if there's more information needed.
Thanks so much in advance!!
UPDATE 2:
Trying to reduce further my current template situation to make it clearer:
The modal with the review is fired from perfume-reviews.html, from this button:
<div class="card-header">
<button type="button" class="btn edit-review" data-perfume_id="{{perfume['_id']}}" data-review_id="{{review['_id']}}" data-toggle="modal" data-target="#editReviewPerfumeModal" id="editFormButton">Edit</button>
</div>
And that opens the modal where my form with the review is (the field in question is a textarea currently displaying a WYSIWYG from CKEditor:
<div class="modal-body">
<form method=POST action="{{ url_for('reviews.edit_review') }}" id="form-edit-review">
<div class="form-group" id="reviewContent">
{{ edit_review_form.review(class="form-control ckeditor", placeholder="Review")}}
</div>
</form>
</div>
Currently this isn't working:
$(document).on("click", "#editFormButton", function (e) {
var reviewText = $(this)
.parents(div.card.container)
.siblings("div#reviewContent")
.children()
.text();
$("input#editReviewContent").val(reviewText);
});
and throws a ReferenceError: div is not defined.
Where am I failing here? (Perhaps in more than one place?)
UPDATE 3:
this is where the button opens the modal, and underneath it's where the review content displays:
<div class="card container">
<div class="row">
<div class="card-header col-9">
<h5>{{review['reviewer'] }} said on {{ review.date_reviewed.strftime('%d-%m-%Y') }}</h5>
</div>
<div class="card-header col-3">
<button type="button" class="btn btn-success btn-sm mt-2 edit-review float-right ml-2" data-perfume_id="{{perfume['_id']}}" data-review_id="{{review['_id']}}" data-toggle="modal" data-target="#editReviewPerfumeModal" id="editFormButton">Edit</button>
</div>
</div>
<div class="p-3 row">
<div class=" col-10" id="reviewContent">
<li>{{ review['review_content'] | safe }}</li>
</div>
</div>
</div>
You can do this with jQuery as when you open the form, the form will automatically show the review content in there. It will be done by manipulating the dom.
Also, add an id to your edit button, in this example, I have given it an id "editFormButton".
Similarly, add an id to the div in which review content lies so that it is easier to select, I have given it an id "reviewContent"
Similarly, add an id to edit_review_form.review like this edit_review_form.review(id='editReviewContent')
<script>
$(document).on("click", "#editFormButton", function (e) {
var reviewText = $(this)
.parents("div.row")
.siblings("div.p-3.row")
.children("div#reviewContent")
.children()
.text();
$("input#editReviewContent").val(reviewText);
});
</script>
Don't forget to include jQuery.
Also, you can do it with pure javascript. You can easily search the above equivalents on google. This article is a good start!

Cannot DELETE mongodb entry

I am creating a blog app using node.js/express/mongoose/mongodb. I am creating a delete route so I can delete posts from my admin panel. I am also using method-override to delete. Whenever I press the button I created to delete a post I am met with an error saying cannot DELETE blogs/(blog name here). Not sure why it is not working, and any help would be greatly appreciated.
Here is the Delete route code
//DELETE BLOG ROUTE
app.delete("/blogs/:slug", function(req, res){
//DESTROY BLOG
Blog.findOneAndRemove({ slug: req.params.slug}, function(err){
if(err){
res.redirect("/admin");
} else {
res.redirect("/admin");
}
})
});
Here is my button to delete on my admin panel
<div class="d-flex justify-content-between">
View Post
Edit Post
<form action="/blogs/<%= blog.slug %>?_method=DELETE" method="POST">
<button class="btn btn-danger"><i class="far fa-trash-alt"></i> Post</button>
</form>
</div>
use blog._slug instead of blog.slug.
Because , mongoose extracts "id" as collections._id
In the Delete Route, you are passing slug as parameter so instead of using the blog.slug.
Use slug only. Example:
<div class="d-flex justify-content-between">
View Post
Edit Post
<form action="/blogs/<%=slug %>?_method=DELETE" method="POST">
<button class="btn btn-danger"><i class="far fa-trash-alt"></i> Post</button>
</form>
</div>

Form modal binding in laravel with vue js

I have 2 models Tour.php
public function Itinerary()
{
return $this->hasMany('App\Itinerary', 'tour_id');
}
and Itinerary.php
public function tour()
{
return $this->belongsTo('App\Tour', 'tour_id');
}
tours table:
id|title|content
itineraries table:
id|tour_id|day|itinerary
In tour-edit.blade.php view I have used vue js to create or add and remove input field for day and plan dynamically.
Code in tour-create.blade.php
<div class="row input-margin" id="repeat">
<div class="col-md-12">
<div class="row" v-for="row in rows">
<div class="row">
<div class="col-md-2">
<label >Day:</label>
<input type="text" name="day[]"
class="form-control">
</div>
<div class="col-md-8">
{{ Form::label('itinerary', " Tour itinerary:", ['class' => 'form-label-margin'])}}
{{ Form::textarea('itinerary[]',null, ['class' => 'form-control','id' => 'itinerary']) }}
</div>
<div class="col-md-2">
<button class="btn btn-danger" #click.prevent="deleteOption(row)">
<i class="fa fa-trash"></i></button>
</div>
</div>
</div>
<div class="row">
<button class="btn btn-primary add" #click.prevent="addNewOption" >
<i class="fa fa-plus"></i> Add Field</button>
</div>
</div>
</div>
I want to populate these fields with their respective data. But all data i.e itinerary belonging to a tour are being displayed in itinerary textbox in JSON format.
My vue js sript is:
<script>
var App = new Vue({
el: '#repeat',
data: {
day:1 ,
rows:[
#foreach ($tour->itinerary as $element)
{day: '{{$element->day}}', plan: '{{$element->plan}}'},
#endforeach
]
},
methods: {
addNewOption: function() {
var self = this;
self.rows.push({"day": "","itinerary":""});
},
deleteOption: function(row) {
var self = this;
self.rows.splice(row,1);
},
}
});
</script>
I would avoid mixing blade into JavaScript, instead the best option is to make an ajax call to an api route which returns your data in json, which can then be processed by Vue:
methods:{
getItinerary(){
axios.get('api/itinerary').then(response => {
this.itinerary = response.data;
})
}
}
However, with this approach you will likely need to use vue-router rather than laravel web routes, which puts us into SPA territory.
If that's not an option (i.e. you still want to use blade templates), you should take a look at this answer I gave the other day which shows you how to init data from your blade templates.
What you seem to be doing is using laravel's form model binding to populate your forms, not Vue, so your model data is not bound to the view. So, you will need to decide which one you want to use. If it's vue you just want to use a normal form and bind the underlying data to it using v-model:
Now any updates in the view will automatically be updated by Vue. I've put together a JSFiddle that assumes you will want to continue using Laravel web routes and blade templates to show you one approach to this problem: https://jsfiddle.net/w6qhLtnh/

AngularJS dynamic routing from index to detailed page

I'm trying to route from an index list of items to a page that will display a detailed view of that item.
In my index view I have a table that iterates through all the items that are saved in the database.
There is a button under the actions column that will take me to events/show route using ng-click="go('events/show')"
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Title</th>
<th class="col-md-2">Actions</th>
</tr>
</thead>
<tbody>
<tr scope="row" ng-repeat="event in events | reverse | filter:filterByUID">
<td>{{event.title}}</td>
<td class="col-md-2">
<div class="btn-group" role="group" aria-label="actions">
<button class="btn btn-primary" ng-click="go('events/show')">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
</button>
<button class="btn btn-primary" ng-click="events.$remove(event)">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
</button>
</div>
</td>
</tr>
</tbody>
</table>
The table looks like this:
In my controller I have:
$scope.go = function ( path ) {
$location.path( path );
};
in my routes.js I have:
.whenAuthenticated('/events/show', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
Everything works so far.
However, what is unclear to me is how do I pass the event id to the eventShow.html page, so I know which item was clicked from the index list, so I can display the detailed information?
My firebase database looks like this:
Check out ui-router, it makes dynamic routing much easier
https://github.com/angular-ui/ui-router
But if you want to keep what you have, you should pass the event id into your path, like such
$scope.go = function ( path, event ) {
$location.path( path + "/" + event.id );
};
.whenAuthenticated('/events/show/:eventId', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
and in your controller, access $stateParams.eventId to load that event.
You should use a variable in your router:
.whenAuthenticated('/events/:id', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
Then you can simply use the ID in your function call:
go('events/:id')
Here's a great tutorial (and I highly recommend watching all of both parts).
And you'll have nicer URLs that can be bookmarked.
One you could pass the UID(uid is just an example for user id) onClick
<tr scope="row" ng-repeat="event in events | reverse | filter:filterByUID">
<td>{{event.title}}</td>
<td class="col-md-2">
<div class="btn-group" role="group" aria-label="actions">
<button class="btn btn-primary" ng-click="go('events/show', event.UID)">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
</button>
<button class="btn btn-primary" ng-click="events.$remove(event)">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
</button>
</div>
</td>
</tr>
Then in your js file
$scope.go = function ( path, uid ) {
$location.path( path + "/" + uid );
};
.whenAuthenticated('/events/show/:eventId', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
Then to query firebase, say you have a field in your objects called uid, you can use startAT and endAT methods.
See here for example
And here to read more on filtering

EmberJS re-use same template, but displays the template twice

I am playing with Ember, and building a basic contact management app to learn Ember. I am following the Emberjs getting started guide. Only instead of doing a "to-do" app, Im doing my own thing in hopes of picking it up better.
My Router, and Routes:
App.Router.map(function() {
this.resource('users', function() {
this.resource('user', { path: ':user_id' });
this.route('motoDigitalTrue');
});
this.resource('about');
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UsersMotoDigitalTrueRoute = Ember.Route.extend({
model: function(){
return App.User.filter(function(user) {
if (user.get('motoDigital')) {
return true;
}
});
},
renderTemplate: function(controller) {
this.render('users', {
controller:controller
});
}
});
Essentially, I have a template named 'users' that I want to reuse. This template lists all the users. I have a sorting button that when clicked, will only display the users who have the motoDigitalTrue property set to true. The sorting is correct, but it just displays another Users template, rather than re-populating the original.
My Users template:
<script type="text/x-handlebars" id="users">
<div class="span10 tableContainer">
<button class="btn btn-primary createUser" {{action createUser}}><i class="icon-plus icon-white"></i> Add a Contact</button>
<div class="btn-group">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">Sort<span class="caret"></span></a>
<ul class="dropdown-menu">
{{#linkTo 'users.motoDigitalTrue' activeClass="selected"}}Receiving MOTO Digital{{/linkTo}}
</ul>
</div>
<div class="tableScrollable">
<table class="table table-striped">
<thead>
<tr>
<th class="nameHead">Name</th>
<th class="companyHead">Company</th>
<th class="emailHead">Email</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name">&nbsp</td>
<td class="company">&nbsp</td>
<td class="email">&nbsp</td>
</tr>
{{#each model}}
<tr>
<td class="name"><i class="icon-user"></i> <strong>{{#linkTo 'user' this }}{{firstName}} {{lastName}}{{/linkTo}}</strong></td>
<td class="company">{{company}}</td>
<td class="email"><i class="icon-envelope"></i> <a {{bindAttr mailto="email"}}>{{email}}</a></td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
<div class="span3">
{{#if isCreateUser}}
<div class="well">
{{partial 'users/createUser'}}
<button {{action 'saveUser'}} class="btn btn-primary"><i class="icon-ok icon-white"></i> Save</button>
</div>
{{else}}
{{outlet}}
{{/if}}
</div>
</script>
I have been unable to find an answer, and any help would be appreciated!
I guess in your case to reuse templates, you should try using a partial, have a look here.
For example, rename your users template to _users
<script type="text/x-handlebars" data-template-name='_users'>
...
</script>
and then use the partial helper to render it
{{partial users}}
Note that {{partial}} takes the template to be rendered as an argument, and renders that template in place. This means that it does not change context or scope. It simply renders the given template with the current scope.
Hope it helps.

Categories

Resources