How to do a Pug for loop with AJAX? - javascript

I am working on a Tinder clone web project for school using Node.js, Express, and Pug that needs to return potential matches with a priority on either distance from the current user or similar interests shared with the current user. When the user first enters their page of potential matches I have the site automatically show the user the best possible matches based on a distance of 5km from their current position. I am sending to the page I render an Array of matches called users and a size of that array called userslen that I pulled from my database in my node file. I then proceed to show the potential matches on the page using this pug for loop:
div(class='container', id='searchResults') <!-- SEARCH RESULTS -->
div(class='row')
- for (var i = 0; i < userslen; i++) {
div(class='col-lg-4 col-md-6 col-sm-12 col-xs-12 usertop')
div(class='row')
div(class='col-lg-12 col-md-12')
a(href='/users/' + users[i].username)
h1=users[i].username
- if (users[i].liked == true) {
span(id='youlikeglyph', class="glyphicon glyphicon-ok")
- } else if (users[i].disliked == true) {
span(id='youdislikeglyph', class="glyphicon glyphicon-remove")
- } else {
- }
div(class='row')
div(class='col-lg-12 col-md-12')
img(id='viewerphoto1', class='userpagephoto', src='/static/uploads/' + users[i].filename)
div(class='row')
- if (users[i].liked == false && users[i].disliked == false) {
div(class='btn-group')
button(id='dislike' + i, class='btn btn-danger btn-lg')
|Dislike
button(id='like' + i, class='btn btn-success btn-lg')
| Like
- } else if (users[i].liked == false && users[i].disliked == true) {
button(id='like' + i, class='btn btn-success btn-lg')
|Like
- } else if (users[i].liked == true && users[i].disliked == false) {
button(id='dislike' + i, class='btn btn-danger btn-lg')
|Dislike
- } else {
- }
div(class='row')
div(class='col-lg-4 col-md-4')
h5="Distance"
h4=users[i].distance + "km"
div(class='col-lg-4 col-md-4')
h5="Same Tags"
h4=users[i].cTags
div(class='col-lg-4 col-md-4')
h5="Popularity"
h4=users[i].popularity
- }
There are two buttons at the top of my page (not shown in the above code) that allow a user to choose to search based on distance or based on tags with a min and max distance/tags-in-common input. When they click on the button of their choice with the min max they have entered I send the data through AJAX to a post that then returns a new array of potential matches based on this new data. Is there a way to make the same for loop I have in the above code but using jQuery once my AJAX response is a success? If there is, what is the best way to go about it? Thank you in advance for your help!

You cannot go back to Jade/Pug once you're on the client. Jade is a templating engine that works on Node. Once you're on the client, it doesn't exist anymore.
You'll need to just loop over your HTML in jQuery, and won't be able to use Jade for this.
Another option is to use one of the client side templating frameworks like Underscore templates/Handlebars/Moustache JS etc.
Using these, you can handle the looping much more elegantly than you can using jQuery, but of course, that really is a call you should take, because this would mean additional payload over the wire.
With one of the templating frameworks, you can define your template in Jade and then reuse it for your iterations

Related

How do I create a better control for rendering custom vue elements?

I have a survey, that people can take. However, if you are one of the first 1000 to fill out the survey you are given a reimbursement. What I am struggling with is how to only show the reimbursement when the users are less than 1000.
The questions in the survey are coming from a CMS backend, while the reimbursement is built on the front end.
<div class="questionContainer" v-if="intentGiven && consentGiven && !surveyComplete">
<div v-if="$store.state.scoring.gameCompleted && this.index == this.QuestionnaireSize && this.ParticipantCount <= 1000">
<ResearchQuestionReimbursement v-on:answered="advanceQuestion"/>
</div>
<div v-else>
<ResearchQuestionMultipleChoice :question="questions[index]"
v-if="questions[index].Type == 'MultipleChoice'"
v-on:answered="advanceQuestion" />
<ResearchQuestionFreeAnswer :question="questions[index]"
v-if="questions[index].Type == 'FreeAnswer'"
v-on:answered="advanceQuestion" />
</div>
</div>
questions[index] is an array of the questions received from the backend CMS. The reimbursement is only supposed to be at the end which is why I have the div wrapped around <ResearchQuestionReimbursement>.
My control logic for the index is:
if (this.index < this.questions.length -1 || (this.$store.state.scoring.gameCompleted && this.index < this.questions.length)) {
this.index++;
console.log(`post: ${this.index}`)
} else {
.....
//required code to save the form
}
Currently, if I have over 1000 users the logic continues and gives me an index undefined error. This makes sense since the index would be 13 and the array would only be 12. I have tried a v-if on <ResearchQuestionReimbursement> to check if there are 1000 users. This resulted in a blank page rendering since it rendered the div but not the content.
What it should do is if there are more than 1000 users it will skip to the else statement.

how to convert unicode and display in browser? reactjs

I am creating a messages page where admin and client can send and receive messages and I am getting some characters which show up, and another developer tells me it's unicode.
something like this
\u2019hey
or this
m\u0159i\u0165 sroun\u011br tro\u0161a hro\u010d ti\u010d s\u00fds\u016f v diplych o zrutr\u00fd. Zlyzli crest\u016fstbukl\u00e1 slokab zlecou, a nij \u0159uk\u00fd tiv. Nij dratl\u00e1h. Tref\u00fd zraditi tin\u011bgle. \u017el\u00edzlod mrytl\u00e9 n\u011bj vosk n\u011bmu z chlyv\u011bt oskev ston div\u011bm. Nivp\u00e1du\u0161 obozr\u016f sre\u0165n\u011bch k\u0159oufl\u00fd a pi\u0148 syb\u0159otru slou\u0161\u00ed. Bliti m\u0159opidtisly vuvle obu ji\u0161 p\u0159a\u010d m\u00e1n\u011b chapupotid \u017eredi hl\u00fdt zrouskod. Vl\u016fbu lkyd k mlozrat, brsk mled\u0159ej koudyzrozr\u00e1 \u0161k\u00fdnid k t\u011bviz. Z kluz studip bruh\u0159ou s d\u00e1tiv\u011b ti\u017elo dikre\u010d. Zu veplev \u0148\u00e1mesk \u010fo\u010d k otil. T\u0159a\u010d i tipo vl\u00e9\u0165o\u0165 k su\u010f kl\u00fdpru \u0161udi\u0148\u010fa
so, how do I convert it to a format more suitable to display on the browser?? using reactjs
these could be icons or anything . not sure.
Here's an example array of what I am getting from server.
I am putting it into an array and then looping through it to display like this
msgContent = arr.map((item,index)=>{
let len = arr.length-1;
if(len ===index){
return <span key={index+100} className={styles.textMsg}>{item}</span>
}else{
return <span key={index+100} className={styles.textMsg}>{item}<br/></span>
}
})
and it still shows up garbled.
could you tell me where am I going wrong here?
Different ways of displaying HTML entities are listed in the documentation. The examples you have in your question are unicode numbers corresponding to the entity, which works perfectly fine as strings in JSX, so if you just want to display them properly, you don't have to change it at all.
Example
function App() {
return <div> {"\u2019hey"} </div>;
}

Angular ng-show multiple conditions (no more than 3 work)

I have a div which I need to show when any of 5 conditions are true.
The problem is that ng-show seems to take into consideration only the first 3 conditions. I don't know if it's only my problem, cause I couldn't find any related problem.
In the following example I kept moving conditions around, but each time only the first 3 conditions are taken into consideration. Whatever condition falls into the 4th position, does not show the div.
Please let me know if you know a work around in case it's not possible to have more than 3 conditions.
It's a pretty big div, so I post only a part:
<div class="row " ng-show="selectedAllP[0] || selectedAllF[0] || selectedAllP || selectedAllD || level">
<div class="row selectedCase">
<div><h3 id="choices">Your choices:</h3></div>
<div class="col-md-4" id="publisher">
<h4>Publishers</h4>
<div class="level" ng-hide="selectedAllP[0] || selectedAllP">Select publisher</div>
<table class="table table-bordered table-striped">
<tbody id="pub">
<tr ng-hide="selectedAllP.Name === ' - Any Publisher -'" ng-repeat="roll in selectedAllP" ng-click="deSelectP(roll)">
<td class="deselect">{{roll.Name}}</td>
</tr>
<tr ng-show="selectedAllP.Name === ' - Any Publisher -'" ng-click="deSelectP(selectedAllP)">
<td class="deselect">{{selectedAllP.Name}}</td>
</tr>
</tbody>
</table>
<p ng-show="noticeAnyPublisher && selectedAllP.Name === ' - Any Publisher -'" class="notice">{{noticeAnyPublisher}}</p>
</div>
And the logic for a part of the div above:
$scope.selectedAllP = [];
$scope.setSelectedP = function (publisher) {
$scope.selectedP = publisher.Name;
// Check if the selected publisher is already in the array
// if it isn't, than push it in the array (else do nothing)
if (publisher.Name == " - Any Publisher -"){
$scope.selectedAllP = publisher;
console.log($scope.selectedAllP);
} else if ($scope.selectedAllP.Name == " - Any Publisher -") {
$scope.noticeAnyPublisher = 'Deselect "Any Publisher" first';
console.log("blblblb");
} else if ($scope.selectedAllP.indexOf(publisher) == -1) {
$scope.selectedAllP.push(publisher);
}
console.log($scope.selectedP, $scope.selectedAllP);
};
$scope.deSelectP = function (dePublisher) {
// Check if the selected publisher is already in the array
// if it is, than remove it from the array (else do nothing)
if (dePublisher.Name == " - Any Publisher -") {
$scope.selectedAllP = [];
$scope.selectedP = 0;
$scope.noticeAnyPublisher = '';
} else {
var idx = $scope.selectedAllP.indexOf(dePublisher);
if (idx != -1) {
$scope.selectedAllP.splice(idx, 1);
$scope.selectedP = $scope.selectedAllP[0].Name;
}
}
};
I want when I choose the 4th condition (in this case || selectedAllD) to show the div above, but as u can see, even if the distributor is selected (and selectedAllD exists in console), the div doesn't show. Check next image to see the div showing when I select the 3rd condition (selectedAllF[0]).
div showing when I select the 3rd condition (selectedAllF[0]). It is showing for the fisrt 2 conditions too. Problem is that its behavior is the same, whatever the order of the conditions (it only considers the first 3 conditions).
You could call a method in your ng-show.
<div class="row " ng-show="showRow()">
and declare that function into your .js file.
$scope.showRow = function () {
return $scope.selectedAllP[0] || $scope.selectedAllF[0] || $scope.selectedAllP || $scope.selectedAllD || $scope.level;
}
No matter how many condition you will pass to ng-show or any ohter directive which accepts expressions. See this docs Angular Expressions. So instead, check all of the parts of you condition statement. In such representation it will be evaluated to true every time when there is AT LEAST 1 statement which returns true. Also it is worth to note that this expression will be evaluated from left to right and UNTIL first true statement will be found.

split a big HTML page to pages on client side

I have a huge HTML page which is mainly a form which is mostly like this:
<FIELDSET id= '1'>
<TABLE>
<TR> </TR>
</FIELDSET>
</TABLE>
.
.
.
<FIELDSET id= 'n'>
<TABLE>
<TR> </TR>
</TABLE>
The number of fieldsets are generated by dynamically on the server.
Question: On the client side I want to do a pagination for this huge page, so that only say,3 fieldset appear per page on the client.
I don't want to change the way page is loading or form is being submitted currently.
Well just a little tips you may use
$('fieldset')
document.querySelectorAll('fieldset')
will return you fields
in order to get show only i .. i+3 fieldsets you can use
var i = 3
$('fieldset').hide().each(function ( index, el) {
if (index >= i && index < i+3) $(el).show()
})
var fieldsets = [].slice(document.querySelectorAll('fieldset'))
for (var index in fieldsets) {
var display = index < i && index >= i+3 ? 'none' : ''
fieldsets[index].style.display = display
}
Pagination won't really help you in any way other than visual if done on the client side (no speed increases, load reductions, etc), but if that's what you want you can do it with DOM manipulation. Something like the following might work for you:
var i=0,sets=document.getElementsByTagName('fieldset'),len=sets.length;
for(;i<len;i+=3) {
// wrap sets[i] through sets[i+2], as long as they exist, in a div
// if i !== 0, hide or minimize the div
}
// add controls to unhide/unminimize each div

Move Through Object List

<div id="team-name">{{teams[0].name}}</div>
<button id="next">Next</button>
When the "next" button is hit I would like the team-name to be the next team name in the list, i.e. 0 becomes 1?
I have a feeling I need JS to do this - but I am not sure how I would use JS to do this.
Also, the list is generated from the server.
UPDATE
{{ }} is part of a templating system - Jinja2 to be precise.
The teams list is passed into the webpage through Jinja2 - so the webpage has access to the entire teams list - I hope that makes sense.
class Team(db.Model):
__tablename__ = 'Team'
name = db.Column(db.String(21))
matches_total = db.Column(db.Integer())
matches_won = db.Column(db.Integer())
matches_lost = db.Column(db.Integer())
Make a list containing the names available as team_names and update your template like this:
<div id="team-name" data-index="0" data-entries="{{ team_names|tojson }}">{{teams[0].name}}</div>
<button id="next">Next</button>
In case you are using flask which seems to be the case, pass this to your render_template() call:
team_names=[t.name for t in Team.query]
Then you can use the following jQuery snippet to do what you want:
$('#next').on('click', function(e) {
e.preventDefault();
var nameElem = $('#team-name');
var entries = nameElem.data('entries');
var index = (nameElem.data('index') + 1) % entries.length;
nameElem.text(entries[index]).data('index', index);
})
Note: This answer assumes the list is not too big.

Categories