jQuery pass dynamically created variable to another function - javascript

I have form partial in Rails, laid out like so:
<div class"row">
<div class="col-md-6" id="top_level">
</div>
</div>
<div class"row">
<div class="col-md-2" id="sub_category1">
</div>
</div>
<div class"row">
<div class="col-md-2" id="sub_category2">
</div>
</div>
<div class"row">
<div class="col-md-2" id="sub_category3">
</div>
</div>
<div class"row">
<div class="col-md-3" id="sub_category4">
</div>
</div>
<div class"row">
<div class="col-md-3" id="sub_category5">
</div>
</div>
It is for selecting categories and sub-categories of items.
listings_controller:
def new
#product_listing = Listing.new
#product_ = Product.find(params[:product_id])
# gon.categories = EbayCategory.all
gon.top_level = EbayCategory.top_level
end
In the model:
scope :top_level, -> { where('category_id = parent_id').order(:id) }
Each category record (17989 of them) has a unique category_id, and a parent_id. As indicated above, the top level category_id = the parent_id for the same record. All the subcategories have their own category_ids, which are the parent_ids of the next level down, and so on, varying between 1 and 5 sub-levels.
I've tried a cascade of view files, which works fine (it renders the correct categories and sub-categories) but I can't pass the listing id that way because I don't know how to transmit 2 ids (one for the parent category, one for the listing id) through the params hash using the link_to url helper, so I lose the id for the listing I'm trying to create while navigating all the sub-categories.
So I'm trying it with jQuery, using the Gon gem. Not only does this mean loading the entire db table (about 7 MB, once I un-comment the line for use in level 2 thru 5) into ram, but I can't figure out how to pass the category_id from the dynamically created top_level list when one of its elements is clicked. There are many levels to go, but right now I'm just trying to console.log the category_id for ONE level, so I can see that it's registering. So far unsuccessful, after trying many different syntaxes and methods, of which this is the latest:
<script type="text/javascript">
$(gon.top_level).each(function(){
$("#top_level").append('<h5>' + this.main_category + " >" + '</h5>').data($(this).category_id);
})
$("#top_level").on('click', 'a', function(){
console.log($(this).data());
});
</script>
...returns
Object {}
to the console.
Any suggestions on how to store ids dynamically with the text category titles?

$('gon.top_level').each(function(){
var lnk = $('<h5>' + this.main_category + " >" + '</h5>')
.find('a').data({'category':$(this).category_id,'anotherKey':'value'});
$("#top_level").append(lnk);
});
$("#top_level").on('click', 'a', function(){
console.log($(this).data('category'));
console.log($(this).data('anotherKey'));
});
To set data use $(elment).data({key:value});
To get data use $(elment).data(key);

Related

Javascript - Use array values dynamically in HTML

My end result is supposed to be a list of objects in html. Bootstrap behind this. I'd like for the list to be created dynamically so I don't have to manually create all the divs because I don't know how many there will be. Here's what I have.
I have an array similar to this:
activities =
[
{
"activityOwner": "Raymond Carlson",
"activityDesc": "Complete all the steps from Getting Started wizard"
},
{
"activityOwner": "Flopsy McDoogal",
"activityDesc": "Called interested in March fundraising Sponsorship"
},
{
"activityOwner": "Gary Busy",
"activityDesc": "Get approval for price quote"
}
]
This is the first part where I'm not sure what to do. I can assign the element ids individually for my html like this but what I'd like to do is count how many elements are in my array and create these for me. I won't know how many there are to make these manually. I'm sure there needs to be a loop but I couldn't figure it out.
document.getElementById('activityowner0').innerHTML = activities[0].activityOwner;
document.getElementById('activitydesc0').innerHTML = activities[0].activityDesc;
document.getElementById('activityowner1').innerHTML = activities[1].activityOwner;
document.getElementById('activitydesc1').innerHTML = activities[1].activityDesc;
document.getElementById('activityowner2').innerHTML = activities[2].activityOwner;
document.getElementById('activitydesc2').innerHTML = activities[2].activityDesc;
etc.
etc.
And then...once I have that part, I'd like to know how to create my html divs dynamically based on how many elements are in my array. Again, right now I don't know how many there are so I'm having to create a bunch of these and then have extras if I have too many.
<div class="container">
<div class="row"></div>
<div class="qa-message-list" id="wallmessages">
<br>
<div class="message-item" id="m0">
<div class="message-inner">
<div class="message-head clearfix">
<div class="user-detail">
<h5 class="handle">
<p id='activityowner0'></p>
</h5>
<div class="post-meta"></div>
</div>
</div>
<div class="qa-message-content">
<p id='activitydesc0'></p>
</div>
</div>
</div>
I know this is a big ask so just pointing me in the right direction would be very helpful. I hope my question was clear and I appreciate it.
One way for you to achieve this would be to loop through the objects in your activities array. From there you can use a HTML template to store the base HTML structure which you can clone and update with the values of each object before you append it to the DOM.
In addition, an important thing to note when generating repeated content in a loop: never use id attributes. You will either end up with duplicates, which is invalid as id need to be unique, or you'll end up with ugly code generating incremental/random id at runtime which is unnecessary. Use classes instead.
Here's a working example:
const activities = [{ "activityOwner": "Raymond Carlson", "activityDesc": "Complete all the steps from Getting Started wizard"}, {"activityOwner": "Flopsy McDoogal","activityDesc": "Called interested in March fundraising Sponsorship" }, { "activityOwner": "Gary Busy", "activityDesc": "Get approval for price quote" }]
const html = activities.map(obj => {
let item = document.querySelector('#template').innerHTML;
item = item.replace('{owner}', obj.activityOwner);
item = item.replace('{desc}', obj.activityDesc);
return item;
});
document.querySelector('#list').innerHTML = html.join('');
<div id="list"></div>
<template id="template">
<div class="container">
<div class="row"></div>
<div class="qa-message-list">
<div class="message-item">
<div class="message-inner">
<div class="message-head clearfix">
<div class="user-detail">
<h5 class="handle">
<p class="activityowner">{owner}</p>
</h5>
<div class="post-meta"></div>
</div>
</div>
<div class="qa-message-content">
<p class="activitydesc">{desc}</p>
</div>
</div>
</div>
</div>
</div>
</template>

Styling a json list

how do i style my json list to material cards?
My json/javascript:
$(document).ready(function(){
var url="getjson.php";
$.getJSON(url,function(data){
console.log(data);
$.each(data.bananas, function(i,post){
var banana =
"<div>"
+"<h3>"+post.name+"</h3>"
+"<h5>"+post.type+"</h5>"
+"</div>";
$(banana).appendTo("#banana-data");
});
now im trying to display it as a nicelt style list of cards but im struggling:
<div class="row">
<div class="col-md-4">
<div id="banana-data" class="box box-widget widget-user">
<div class="widget-user-header bg-aqua-active">
<h3 class="widget-user-username"></h3>
<h5 class="widget-user-desc"></h5>
</div>
</div>
</div>
</div>
But my content appears outside the style of my
I tried using list as follows:
<ol id="banana-data">
<div class="row">
<div class="col-md-4">
<div class="box box-widget widget-user">
<div class="widget-user-header bg-aqua-active">
<h3 class="widget-user-username"></h3>
<h5 class="widget-user-desc"></h5>
</div>
</div>
</div>
</div>
</ol>
var banana =
"<ol>"
+"<h3>"+post.cname+"</h3>"
+"<h5>"+post.sub_type+"</h5>"
+"</ol>";
$(banana).appendTo("#banana-data");
});
The content displayed inside my style,but the entire list of items in the json file was sitting on the same card,and not separating to create multiple styled cards.
this is my php file that converted the data in the msqli table to json:
<?php
require_once 'dbconfig.php';
$posts = array();
$query = "SELECT * FROM bananas";
$stmt = $db_con->prepare($query);
$stmt->execute();
while($row=$stmt->fetch(PDO::FETCH_ASSOC)) {
$posts['bananas'][] = $row;
}
echo json_encode($posts);
?>
I think you have not append it.You have to use after() method like this..
$("#banana-data").after(banana);
So change your script:
$(document).ready(function(){
var url="getjson.php";
$.getJSON(url,function(data){
console.log(data);
banana = "";
$.each(data.bananas, function(i,post){
banana +=
"<div>"
+"<h3>"+post.name+"</h3>"
+"<h5>"+post.type+"</h5>"
+"</div>";
});
$("#banana-data").after(banana);
Very Good Question:
There are multiple libraries you can use for parsing and styling json:
Handlebars is a library that allows you to parse your json with ease and include each json object in your html
The other one is Moustache.But my solution for you is handlebars.
First turn your json into an actual jsonfile as follows...
$json_data = json_encode($posts);
file_put_contents('ldt.json', $json_data);
Add those two lines in your php instead of your echo.ldt is the filename,you can call it whatever you want.
Nextstep:parse the json file using handlebars..
var yourRequest = new XMLHttpRequest();
yourRequest.open('GET', 'ldt.json');
Then in handlebars on create a function and..instruct handlebars to generate html(myhtml) of parsed json and assign it to an id called:eg mycontainer:
var rawTemplate = document.getElementById("thisTemplate").innerHTML;
var myContainer = document.getElementById("my-container");
my.innerHTML = ourGeneratedHTML;
Then in your html:
<div id="my-container"></div>
<script id="thisTemplate" type="text/x-handlebars-template">
//And here call your objects:Example
{{#each bananas}}
<div class="col-md-4">
<div class="box box-widget widget-user">
<div class="widget-user-header bg-black" style="background: url('{{img}}'>) center center;">
<h3 class="widget-user-username"><b>{{name}}</b></h3>
<h5 class="widget-user-desc">({{type}})</h5>
Just make sure your css actually creates your so called cards etc..and your card list will populate your page exactly as you have styled it with all the objects youve parsed.
Ive simply added small snippets of code.For more information,check out:
Handlebars
Theres nothing wrong with just using ajax and create your own elements,but if you want to kill two birds with one stone,use libraries.
There are also alot of tuts on youtube you can watch.I hope this helps

I have a 100 button, click each button to display its corresponding bomb box, With javascript and angular

a button corresponding to a prompt box,each box is different shells;Although implements the desired function, but my code is too complicated, and that there is no simple way. how can I do? This is my code
<--html button-->
button1
button2
...
button100
<--html pop box-->
<div class="note1" style="display:none;">
<img class="title-css" src="note1.png">
<p class="one">note1</p>
</div>
...
<div class="note100" style="display:none;">
<img class="title-css" src="note100.png">
<p class="one">note100</p>
</div>
<--angular js-->
$scope.showRulePop = function(index) {
for(var i=1;i<=8;i++) {
$('.note'+i).hide();
}
$('.note'+index).show();
};
Well first of all, don't use jQuery, unless your in the directive level of angular jQuery have nothing to do there.
First let's get rid of the links part using a simple ng-repeat :
<--html button-->
<div ng-repeat="button in buttons">
{{button.label[i]}}
</div>
// JS in the controller
$scope.buttons = [{
label:'button1'
},{label:'button2'}];
As you can see i declare in the javascript all your buttons and i just loop over it.
Now the "bombox" or whatever it is let's make it a simple template :
<div class="{{currentnote.class}}" ng-if="currentNote">
<img class="title-css" src="{{currentNote.img}}">
<p class="one">{{currentNote.content}}</p>
</div>
// and use ng-repeat for the eight first when there is no button selected
<!-- show 1 to 8 if note current note selected -->
<div ng-repeat="button in buttons1To8" ng-if="!currentNote">
<div class="{{button.note.class}}">
<img class="title-css" src="{{button.note.img}}">
<p class="one">{{button.note.content}}</p>
</div>
</div>
// JS
$scope.buttons = [{
label:'button1'
note:{class:'note1', img:'note1.png', content:'note1'//assuming no HTML or you' ll need something more
}},{label:'button2', note:{...}}, ...];
$scope.showRulePop = function(index){
$scope.currentNote = $scope.buttons[index].note;
}
$scope.buttons1To8 = $scope.buttons.slice(0, 8);//0 to 7 in fact
That's all, no need of jQuery.

jQuery script works just for one button on the product catalog

I have a product catalog and I want to save on localstorage the products selected by the user.
The jquery script only gets the first product on each page on each click... it simply ignores the rest of the products, and the console prints the same object.
Here is my HTML+TWIG code
{% for products in pagination %}
<div class="product col-sm-6 col-lg-6 col-md-6 hero-feature">
<div id="{{attribute(products ,'id')}}" class="product thumbnail">
<img id="prodImage" class="img-responsive img-rounded" src="{{attribute(products ,'image')}}" style="width:150px;height:150px" >
<div class="product caption">
<h4 id="prodPrice" class="product pull-right"><b>{{ attribute (products, 'price') }}Lei</b></h4>
<h4 id="prodName" style="height:100px;width:200px;">
<a id="prodLink"
href="{{ attribute (products, 'affiliatelink') }}"
target="_blank">{{attribute ( products, 'name') }}</br></a>
</h4>
</div>
<div class="add-to-cart" class="product" >
<button id="buttonProd" class="oneButton btn btn-danger " value="Save" type="button">Adauga</button>
</div>
</div>
</div>
{% endfor %}
Here is the jquery script
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type='text/javascript' defer="defer">
$(document).ready(function() {
var prodId = $('.thumbnail').attr("id");
$("#buttonProd").on("click", 'button', function(event){
event.preventDefault();
var products =
{
prodID :$('.thumbnail').attr("id"),
prodName :$('#prodName').text(),
prodPrice :$('#prodPrice').text(),
prodImage :$('#prodImage').attr('src'),
prodLink :$('#prodLink').attr('href')
};
localStorage.setItem('products-' + prodId, JSON.stringify(products));
var retrievedObject = JSON.parse(localStorage.getItem('products-' + prodId));
console.log('retrievedObject: ', retrievedObject);
});
});
</script>
How can I make the script take each product proprieties on click. Thank you in advance.
In JQuery, the assumption is made that all ID's will be unique. Since you're repeating "#buttonProd", JQuery will only select the first one to bind the action to. If you want to bind to multiple elements, you'll either have to give each button a unique ID or use some other selector to attach your jQuery functionality.
From the documentation for the ID Selector:
Calling jQuery() (or $()) with an id selector as its argument will return a jQuery object containing a collection of either zero or one DOM element.
As the other answers have eluded to you should be using a different selector. I recommend simply adding a descriptive class to each element you wish to grab data from.
<div class="products">
<div class="product">
<div class="productName">First Product</div>
<div class="productPrice">5.00</div>
</div>
<div class="product">
<div class="productName">Second Product</div>
<div class="productPrice">4.00</div>
</div>
<button id="buttonProduct">Log Product Info</button>
</div>
If you notice in the above HTML each div that contains a product's name or a product's price shares the same class productName and productPrice respectively. In addition each container class for each product has the same class as well: product.
This will allow us to utilize the JQuery class selector $(".") to iterate over each product container. We do this using the .each() function. We use the .find() function to locate productName and productPrice in each iteration of the loop.
$(document).ready(function() {
$("#buttonProduct").click(function(){
var products = [];
// Notice the dot in $(".product") that is the class selector
// the .each iterates over every element that matches the preceding selector
$(".product").each(function(){
products.push({
// The .find() selects an element inside $(this)
// that matches the parameter (either .productName or .productPrice
productName : $(this) .find('.productName').html(),
productPrice : $(this).find('.productPrice').html()
});
});
console.log(products);
});
});
For a working example of this check out this jsfiddle. (I noticed you had console.log() in your code so that's where I output the result.)
You want to save the product in localStorage on clicking of corresponding button right?
for that instead of binding click event via jquery, put it in html and move the click code to a function saveProduct()
HTML:
<button id="buttonProd" class="oneButton btn btn-danger " value="Save" type="button" onclick="saveProduct({{attribute(products ,'id')}})">Adauga</button>
JS:
function saveProduct(event, prod_id){
event.preventDefault();
var products =
{
prodID :prod_id,
prodName :$('#'+prod_id+' #prodName').text(),
prodPrice :$('#'+prod_id+' #prodPrice').text(),
prodImage :$('#'+prod_id+' #prodImage').attr('src'),
prodLink :$('#'+prod_id+' #prodLink').attr('href')
};
localStorage.setItem('products-' + prod_id, JSON.stringify(products));
var retrievedObject = JSON.parse(localStorage.getItem('products-' + prod_id));
console.log('retrievedObject: ', retrievedObject);
});
}
You need to change #buttonProd from an id to a class. An id is only supposed to appear once on a page, so jQuery will only apply it to one. Change it to a class in your markup and your script and it should work fine. Same for prodName, prodPrice, prodImage, and prodLink. Anything that will be going inside the loop needs to be a class, and any id should be unique, like you have {{attribute(products ,'id')}}

How can a data-bind to an element within a Kendo-Knockout listview?

I have a rather sophisticated template for Kendo ListView using knockout-kendo.js bindings. It displays beautifully. My problem is that I need to use the visible and click bindings in parts of the template, but I can't get them to work. Below is a simplified version of my template. Basically, deleteButtonVisible determines whether the close button can be seen, and removeComp removes the item from the array.
<div class='template'>
<div >
<div style='display:inline-block' data-bind='visible: deleteButtonVisible, event: {click: $parent.removeComp}'>
<img src='../../../Img/dialog_close.png'></img>
</div>
<div class='embolden'>#= type#</div><div class='label1'> #= marketArea# </div>
<div class='label2'> #= address# </div>
<!-- more of the same -->
</div>
The view model:
function CompViewModel() {
var self = this;
self.compData = ko.observableArray().subscribeTo("compData");
self.template = kendo.template(//template in here);
self.removeComp = function (comp) {
//do something here
}
}
html:
<div class="row" >
<div class="col-md-12 centerouter" id="compDiv" >
<div class="centerinner" id="compListView" data-bind="kendoListView: {data: compData, template: template}"></div>
</div>
</div>
finally, sample data:
{
type: "Comparable",
marketArea: "",
address: "2327 Bristol St",
deleteButtonVisible: true
},
Take in count that the deleteButtonVisible must be a property on the viewModel linked to the view.You are not doing that right now. The click element can v¡be access from the outer scope of the binding and remove the $parent.He take the method from the viewmodel. Take in count that every thing that you take on the vie must be present on the view model for a easy access.

Categories

Resources