send data from ajax GET to ejs file - javascript

I am retrieving some user data with an ajax GET call, and want to display each user in a bootstrap card, so that I can filter these on the page using jQuery.
Currently, I get the data, iterate over each user and append some card elements to the <div class="card-deck"></div>:
jQuery:
$(document).ready(function() {
$.getJSON('/api/user/all')
.then(data => {
$.each(data, function (i, user) {
var userCard = '<div class="col-md-auto mb-4">' +
'<div class="card matches mx-auto" style="width: 18rem; height: 24rem;">' +
'<div class="card-body">' +
'<h5 class="card-title">' + user.username + '</h5>' +
'<p class="card-text">' + user.jobTitle + '</p>' +
'<p class="card-text">' + user.city + '</p>' +
'</div>' +
"</div>" +
"</div>";
$('#userList').append(userCard);
});
})
})
ejs:
<div class="row">
<div class="card-container align-items-left">
<div class="card-deck" id="userList">
// cards go here ...
</div>
</div>
</div>
This works, but there will be a lot of html that goes into building the cards, so I would prefer to send the entire user object (below this is user) to the .ejs file, so that I can build the card there:
<div class="row">
<div class="card-container align-items-left">
<div class="card-deck" id="userList">
<div class="col-md-auto mb-4">
<div class="card matches mx-auto" style="width: 18rem; height: 24rem;">
<div class="card-body">
<h5 class="card-title"><%=user.username%></h5>
<p class="card-text"><%=user.jobTitle%></p>
<p class="card-text"><%=user.city%></p>
</div>
</div>
</div>
</div>
</div>
</div>
Is this a job fo the jQuery data method?

You need to implement an endpoint that fetches user information and forms the template for your userList div and sends the data back as a plain html string.
This endpoint has to be called from the client via an ajax call and set the response html to the div
Server
app.get('/api/user/all',(req, res){
//get user data
const data = [{username:"john",jobTitle:"a",city:"b"},{username:"doe",jobTitle:"a",city:"b"}];
res.render('userTemplate', {users:data} ,function(err, html) {
res.send(html);
});
Client
$.ajax({
url: "/api/user/all",
cache: false,
success: function(html){
$("#userList").innerHtml(html);
}
});
userTemplate.ejs
<% for(var i=0; i < users.length; i++) { %>
<div class="col-md-auto mb-4">
<div class="card matches mx-auto" style="width: 18rem; height: 24rem;">
<div class="card-body">
<h5 class="card-title"><%= users[i].username %></h5>
<p class="card-text"><%= users[i].jobTitle %></p>
<p class="card-text"><%= users[i].city %></p>
</div>
</div>
</div>
<% } %>

EJS is server-side code.
If you want to generate your HTML server side instead of modifying the DOM client side, then replace getJSON with an ajax call (with dataType: "html") and change /api/user/all to an endpoint (which you will have to create) which gets the data and inserts it into an EJS template.

Related

Show posts with ajax - Use of undefined constant postObj - assumed 'postObj'

I have a homepage where there is a menu with some categories and below there are the latest posts:
<ul class="Categories__Menu">
#foreach($categories->take(6) as $category)
<li class="ative">
{{$category->name}}
</li>
#endforeach
</ul>
<div class="row" id="posts">
#foreach($posts as $post)
<div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-4">
<div class="card">
<img class="card-img-top" src="{{$post->image}}" alt="Card image cap">
<h5 class="card-title">{{$post->name}}</h5>
<div class="card-footer d-flex justify-content-between align-items-center">
More
</div>
</div>
</div>
#endforeach
</div>
I want that when each category is clicked to show only the posts of that category in the homepage, but in the same homepage, not in a specific category page.
So I have this Ajax:
$(function() {
$("a[name='category']").on('click', function(){
var category_id = $(this).attr("id");
$.ajax({
url: '{{ route('category.posts',null) }}/' + category_id,
type: 'GET',
success:function(result){
$('#posts').empty();
$.each(result,function(index, postObj){
$('#posts').append("<p>"+postObj.name+"</p>");
});
console.log(result);
},
error: function(error) {
console.log(error.status)
}
});
});
});
And its working fine, but instead of show just this:
$('#posts').append("<p>"+postObj.name+"</p>");
I want to show the posts with the real html above like:
<div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-4">
<div class="card">
<img class="card-img-top" src="{{$post->image}}" alt="Card image cap">
<h5 class="card-title">{{$post->name}}</h5>
<div class="card-footer d-flex justify-content-between align-items-center">
More
</div>
</div>
</div>
So Im using like this in ajax:
$("a[name='category']").on('click', function(){
var category_id = $(this).attr("id");
alert(category_id);
$.ajax({
url: '{{ route('category.posts',null) }}/' + category_id,
type: 'GET',
success:function(result){
$('#posts').empty();
$.each(result,function(index, postObj){
//$('#posts').append("<p>"+postObj.name+"</p>");
$('#posts').append("<div class=\"col-12 col-sm-6 col-lg-4 col-xl-3 mb-4\">\n" +
" <div class=\"card box-shaddow\">\n" +
" <img class=\"card-img-top\" src=\"{{postObj.image}}\" alt=\"Card image cap\">\n" +
" <h5 class=\"card-title h6 font-weight-bold text-heading-blue\">{{postObj.name}}</h5>\n" +
" <div class=\"card-footer d-flex justify-content-between align-items-center\">\n" +
"\n" +
" More\n" +
" </div>\n" +
" </div>\n" +
" </div>");
});
console.log(result);
},
error: function(error) {
console.log(error.status)
}
});
});
But it appears an error:
Use of undefined constant postObj - assumed 'postObj'
Do you know why?
PostController:
public function WhereHasCategory(Request $request)
{
$posts = Post::whereHas('categories', function ($categories) use (&$request) {
$categories->where('id',$request->id);
})->get();
return response()->json($posts);
}
Route to the ajax part:
Route::get('posts/where/category/{id}','\PostController#WhereHasCategory')->name('category.posts');
Method to return the homepage view:
public function index(){
return view('home')
->with('categories', Category::orderBy('created_at', 'desc')->get())
->with('posts', Post::orderBy('created_at','desc')->take(8)->get());
}
Make sure you refer to variable in Blade template with $postObj, not postObj. I can see you use it without $, like postObj.image in your tag.

How to add divs with some classess to another div (inside each other) in html / javascript

I want to list my products from database by clicking on category in html/view.
Firstly I created it in HTML (static) just to check how this is going to look, and it looks lik this:
Here is my html:
<div class="col-md-8" style="margin-top: -15px;">
<div class="products row">
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coke.png">
<p class="product-title">
Product no1
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/pepsi.png">
<p class="product-title">
Product no2
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coffe.png">
<p class="product-title">
Product no3
</p>
</div>
</div>
</div>
</div>
And now I want to create this block dynamically:
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coffe.png">
<p class="product-title">
Product no N
</p>
</div>
</div>
Here is what I've tried so far:
<script>
function onSelectGroup(Id) {
$.ajax({
method: "GET",
url: "Products/GetProductsByCategoryId",
data: { categoryId: Id }
})
.done(function (response) {
//In response I am getting my products, looping through them to create divs like in code above
for (var i = 0; i < response.length; i++) {
//<div class="col-md-3">
// <div class="article-holder">
// <img class="img-responsive" src="images/picture_not_available_400-300.png">
// <p class="product-title">
// Product no 1
// </p>
// </div>
// </div>
//Trying to append it to my .product class because it's parent of this divs above
$(".products").append('<div class="col-md-3"></div>');
$(".products).appendChild('<div class="article-holder"></div>');
}
})};
</script>
But this is not working unfortunatelly... I tried few another things, but this appendings are not working as expected :/
Thanks guys for any help
Cheers
There are many answers posted for the question which might solve the issue with the javascript code. I am posting a different approach as OP specifically requested for it in the comments.
At times, i do not like to build complex HTML markup in javascript with jQuery ( i afraid i might make typos (missing "" or ' etc..). In that case, i would like to have my action method return a view result (the HTML markup) as the response of my ajax call and i can simply update the DOM with that as needed.
public ActionResult GetProductsByCategoryId(int categoryId)
{
var p = db.Products.Where(a=>a.CategoryId==categoryId).ToList();
return PartialView("ProductList",p);
}
Now i will have a partial view called ProductList.cshtml, which is strongly typed to a list of products and i can loop through the items passed to it and render whatever markup i want.
Here is a simple example where i am rendering a div with css class col-md-3 for each item in the collection passed to it. You can update it to render whatever markup you want to render.
#model List<Product>
#foreach (var item in Model)
{
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="#item.ImageUrl">
<p class="product-title">
#item.Name
</p>
</div>
</div>
}
Now all i have to do is, call this action method, and use the response to update my DOM. Let's give an Id to the container div which we will update
<div class="col-md-8" >
<div id="product-list" class="products row">
</div>
</div>
Now when the ajax call receives a response from server, update the inner html of the DOM element with Id product-list
$.ajax({
method: "GET",
url: "#Url.Action("GetProductsByCategoryId","Products")",
data: { categoryId: 2345 }
})
.done(function(response) {
$("#product-list").html(response);
}).fail(function(a, a, e) {
alert(e);
});
Keep in mind that, now you are getting a bigger payload (the resulting HTML)
from the server compared to the JSON data. So use this approach as you feel appropriate to do so. With this approach, i can use the C# methods in my partial view (For example, to build the path to an image in a location/ use Html helper methods etc)
I you create the dom element like any string, and append it to the container
function onSelectGroup(Id) {
//In response I am getting my products, looping through them to create divs like in code above
for (var i = 0; i <10; i++) {
let item = `<div class="col-md-3">
<div class="article-holder">
<img class="img-responsive" src="images/picture_not_available_400-300.png">
<p class="product-title">
Product no ${i}
</p>
</div>
</div>`
//Trying to append it to my .product class because it's parent of this divs above
$(".products").append(item);
}
};
onSelectGroup();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col-md-8" style="margin-top: -15px;">
<div class="products row">
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coke.png">
<p class="product-title">
Product no1
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/pepsi.png">
<p class="product-title">
Product no2
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coffe.png">
<p class="product-title">
Product no3
</p>
</div>
</div>
</div>
</div>
You can create a new element with jquery and fill it properly
for (var i = 0; i < response.length; i++) {
//<div class="col-md-3">
// <div class="article-holder">
// <img class="img-responsive" src="images/picture_not_available_400-300.png">
// <p class="product-title">
// Product no 1
// </p>
// </div>
// </div>
//Trying to append it to my .product class because it's parent of this divs above
var newelem = $('<div class="col-md-3"></div>');
var artholder = $('<div class="article-holder"></div>');
newelem.append(artholder);
artholder.append(<your-image><your article title>);
}
You was close; all you needed to do was create an element for each item in the results object. I've used test data in the example.
https://jsfiddle.net/tw0vrpyy/
var response = {
item1: {
id: "id1",
title: "title1",
img: "img_src1.jpg"
},
item2: {
id: "id2",
title: "title2",
img: "img_src2.jpg"
}
};
var product = document.getElementsByClassName('response')[0];
Object.keys(response).forEach(function(key) {
var el = '<div class="col-md-3">' +
'<div class="article-holder">' +
'<img class="img-responsive" src="'+ response[key].img +'">' +
'<p class="product-title">' +
response[key].title +
'</p>' +
'</div>' +
'</div>';
product.innerHTML += el;
});

ng-repeat is showing data that is not there

I am using data load dynamically through a function and then populate using ng-repeat.
Below is the controller code.
$scope.loadproducts = function(item_id) {
var pdata = $.param({
item_id : item_id,
});
$http({
method: 'POST',
url: baseurl + 'api/get_items_in_category_cart',
data: pdata,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(function successCallback(response) {
$scope.items = response.data.products;
$scope.description = response.data.description;
console.log($scope.items);
$timeout(apply_tooltip, 500);
}, function errorCallback(response) {
});
};
View
<div class="container col-md-6" ng-repeat="item in items">
<div class="panel panel-primary">
<div class="panel-heading">
<h4 class="panel-title">{{ item.title }}</h4>
</div>
<div class="panel-body">
<div class="col-md-3 col-xs-5"><img ng-src="{{ item.thumbnail }}"></div>
<div class="col-md-9" style="">
<div class="row">
<div class="col-md-12">
<span style="font-size: 14px; font-weight: 500;">{{ item.description }}</p>
</div>
</div>
<div class="row">
<div class="col-md-4 text-right" style=" text-align: left;">
<p>{{item.price | currency:"NZ $"}}</p>
</div>
<div class="col-md-8" style=" text-align: left;">
<input type="text" value="{{item.qty}}" style="width:50px; height: 28px; line-height: 28px;" readonly id="qty_{{item.id}}"/>
</div>
</div>
</div>
</div>
</div>
</div>
Upon initial page load the the code does what it is supposed to do.
There is a proceed button where the user gets taken to another page.
If the user goes back, the items are supposed to reload again.
The issue is during the reload the text box that is supposed to show the quantity for each item ->> value="{{item.qty}}" seems to show the same qty for all qty text boxes regardless of the original qty they had.
The console.log($scope.items) shows the proper value that it is supposed to have. It's just the display that is showing the wrong qty.
Any idea guys?
If your data is loaded correctly, you can go in two ways:
1 - Try to use a ng-model in your input
<input type="text" ng-model="item.qty" style="width:50px; height: 28px; line-height: 28px;" readonly id="qty_{{item.id}}"/>
You can either remove the 'readonly' property and add a ng-disabled="true".
2 - You can try to clear your list before you get the new values. So, before you load again your values from back-end you could just clear your data:
$scope.items = [];
And put the data again when the request is completed.
Note that this second solution it isn't conventional, and should be used in case that you can't find out another solution.

How to make two times for a loop in javascript?

I want to javascript loop for wrapping two line of products layouts after i got a respond from ajax.
Purposed: I want to get result like below
<div class="owl-item">
<div class="row item">
<div class="product">
<div class="image">
<img src="asset/img/main/9.jpg" alt="img">
<div class="promotion"><span class="discount">4</span></div>
<div class="description">
<div class="price"><span>1.0000</span></div>
<h4></h4><p>short detial</p>
</div>
</div>
</div>
</div>
<div class="row item">
<div class="product">
<div class="image">
<img src="9.jpg"alt="img">
<div class="promotion"><span class="discount">4</span></div>
<div class="description">
<div class="price"><span>2.0000</span></div>
<h4></h4>
<p>short detial</p></div>
</div>
</div>
</div>
</div>
As the above html planned I want to loop <div class="owl-item"> one times then I will loop <div class="row item"> two times So my html layout will wrap my products as the below images.
$.ajax({
type: "GET",
url: "<?php echo base_url('main/dataaccess'); ?>",
dataType: "json",
cache: false,
success: function (data, st) {
if (st == 'success') {
$.each(data, function (i, obj) {
var out = '<div class="row item">';
out += '<div class="product">';
out += '<div class="image">';
out += '<img src="asset/img/main/9.jpg" alt="img" class="img-responsive">';
out += '<div class="promotion"><span class="discount">' + obj.prodId + '</span> </div>';
out += '<div class="description"><div class="price"><span>' + obj.prodPrice + '</span></div><h4>' + obj.prodName + '</h4>';
out += '<p>short detial</p>';
out += '</div>';
out += '</div>';
$(out).appendTo("#ps");
});
$("#ps").owlCarousel({
navigation: false,
pagination: false,
items: 8,
itemsTablet: [408, 2]
});
}
}
});
This is the layout that i want to get
But as my code I will got layout as below that I don't want it
Are one of those classes that are applying to your div set as display:inline-block ? I suggest inspecting the rendered page to confirm that the divs are display: block.

How can I get specific information from an external api to my ng-repeat

main.html
<div class="row" ng-repeat="post in myBlogPosts.slice().reverse()">
<br>
<div class="col-md-9 text-center">
<a href="#/blog-post/{{post._id}}">
<div class="thumbnail mTextBg customShadow">
<br>
<img class="img-responsive" src="http://placekitten.com/700/400" alt="">
<div class="caption">
<h3>{{post.imdbId}}</h3>
<p>{{post.blogContent}}</p>
</div>
</div>
</a>
</div>
<div class="col-md-3">
// I WANT THIS PART !!
<div class="well sideBars customShadow">
<img class="img-responsive" ng-src="{{film.Poster}}" title="{{film.Title}}">
<h4 class="text-center">{{film.Title}}</h4>
<p class="text-center" style="margin-bottom: 2px;"><b>Year:</b> {{film.Year}}</p>
<p class="text-center"><span class="customMargin">Runtime: {{film.Runtime}}</span></p>
<p class="text-center"><span class="customMargin">Director: {{film.Director}}</span></p>
<p class="text-center"><span class="customMargin">Writer: {{film.Writer}}</span></p>
<p class="text-center"><span class="customMargin">Actors: {{film.Actors}}</span></p>
</div>
</div>
</div>
This is part of my main.html . In h3 and p tags, I get imdbId and blogContent from my database and put it in ng-repeat in order to traverse blog posts in list. I want to be able get other information(under // I WANT THIS PART) for every post in myBlogPost.
MainController.js
var refresh = function() {
$http.get('/myDatabase').success(function(response) {
$scope.myBlogPosts = response;
});
};
refresh();
This part work as expected when page loaded.
I need also these parts in Main Controller ;
var onGetFilmData = function (data) {
$scope.film = data;
};
var onError = function (reason) {
$scope.error = reason;
};
imdb.getImdbInfo(-- need Id --).then(onGetFilmData, onError);
But I need to put each post id somehow in order to get specific data from Imdb api.
Imdb.js
(function(){
var imdb = function($http){
var getImdbInfo = function (id) {
return $http.get('http://www.omdbapi.com/?i=' + id + '&plot=short&r=json')
.then(function(response){
return response.data;
});
};
return{
getImdbInfo: getImdbInfo
};
};
var module = angular.module('myApp');
module.factory('imdb', imdb);
})();
If I delete id part and put a specific id string in getImdbInfo function, all post in main.html fill with just one film information. I want to fetch those data for each film in my database(I am holding imdb id of each film in my database).
MainController
var jsonObj = {};
var refresh = function() {
$http.get('/myDatabase').success(function(response) {
jsonObj = response;
for(var i = 0; i < jsonObj.length ; i++){
jsonObj[i].title = '';
}
for(var i = 0; i < jsonObj.length ; i++){
(function(i) {
imdb.getImdbInfo(jsonObj[i].imdbId).then(function (data) {
jsonObj[i].title = data.Title;
});
})(i);
}
$scope.myBlogPosts = jsonObj;
});
};
refresh();
main.html
<div class="row" ng-repeat="post in myBlogPosts.slice().reverse()">
<br>
<div class="col-md-9 text-center">
<a href="#/blog-post/{{post._id}}">
<div class="thumbnail mTextBg customShadow">
<br>
<img class="img-responsive" src="http://placekitten.com/700/400" alt="">
<div class="caption">
<h3>{{post.imdbId}}</h3>
<p>{{post.blogContent}}</p>
</div>
</div>
</a>
</div>
<div class="col-md-3">
<!-- Side Widget Well -->
<div class="well sideBars customShadow">
<h4 class="text-center">{{post.title}}</h4>
</div>
</div>
</div>
I solve my problem with adding response from Imdb to my json object which is coming from database. So I can easily use them in ng-repeat.

Categories