Javascript + jquery issue - javascript

I am getting a bunch of "tasks" from a database and formatting this way with .each function.
$.getJSON('tarefas.php?acao=2', function(data) {
$.each(data,function(){
$('.task-item').parents('ul').prepend('
<li class="task-item nova">
<div class="status"></div>
<li id="'+(this).id+'">
<span class="id">ID: </span>
<span class="id" id="id_tarefa">'+(this).id+'</span>
<div class="task-comment">
<span class="helper-subtle">14/06/2011 14:32</span> database data
<div class="ico-delete"></div>
</div>
</li>'
});
});
And now I need to send this data to a php file and add more one log line when the bt-salvar is pressed.
<div class="task-log">
<span class="helper-subtle">14/06/2011 14:32</span> database data
<div class="ico-delete"></div>
</div>
I am using this code:
$('.bt-salvar').click(function() {$.ajax({type: 'POST',
url: 'tarefas.php?acao=3',
data: {'dados':'{"tarefa":"'+$('#id_tarefa').text()+'"}'},
success: function(){
$('#'+$('#id_tarefa').text()).prepend('
<div class="task-comment">
<span class="helper-subtle">data</span>
'+$('textarea').val()+
'<div class="ico-delete"></div>
</div>'
);
});
});
When I pressed the bt-salvar this line is added but just in 1 task. I should the problem is in way that I am referencing the id ($('#'+$('#data-group').text())).
I need to get the exact current task and put the log line just on this task. I don´t know how can I reference the current tasks that was generated by the first.getJSON part of the page.

You have a <span class="id" id="id_tarefa">...</span> but it is being generated with $.each() so presumably you have several of them - identifiers must be unique.

Related

Dynamic p tag depends on dropdown select - Javascript Laravel

I guess its simple for javascipt masters . Basically I want to change price(which is default by large) when i select the small size pizza .. Ive tried something but nothing happened
Here is HTML
<div class="row portfolio-containerr">
#foreach($product as $p)
<div class="col-lg-3 text-center portfolio-item {{$p->category_id}} ">
<div class="card bg-transparent " style="width: 14rem;">
<img class="card-img-top" src="{{asset('front/')}}/assets/img/1.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title text-center">{{$p->title}}</h5>
<p class="card-text text-center">{{$p->description}}</p>
<p product-id="" style="color:#ff4a17;font-size: 20px ">{{$p->price}}</p>
<div class="btn-group">
<button type="button" class="btn btn-danger">Large</button>
<button type="button" class="btn btn-danger dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu">
<a product-id="{{$p->id}}"class="dropdown-item size-click" href="#">Large</a>
<a product-id="{{$p->id}}"class="dropdown-item size-click" href="#">Small</a>
</div>
</div>
Controller
public function getData(Request $request){
$product = Product::findOrFail($request->id);
return response()->json($product);
}
javascript
$(function(){
$('.portfolio-item').on('click', '.size-click', function(){
id = $(this)[0].getAttribute('product-id');
$.ajax({
type:'GET',
url:'{{url("/getData")}}',
data:{id:id},
success:function(data){
console.log(data);
$('p')[0].getAttribute("product-id", data.id);
$('p[product-id="data.id"]').text(data.priceS);
}
})
})
});
That code has several issues which I'll try to address one by one.
PHP/HTML
In your HTML (generated by PHP), you are using a non-existent attribute product-id to attach an ID to several elements. Instead of "inventing" your own attributes, you should use a data- attribute here, because that's what they are made for. For example, instead of
<a product-id="..." class="..." href="#"> ... </a>
you should use
<a data-product-id="..." class="..." href="#"> ... </a>
This goes for all elements that currently have a product-id attribute.
Fixed PHP/HTML
Using data- attributes.
Note: Both <a>-elements receive the same product ID, regardless of the product's size – is that correct?
<div class="row portfolio-containerr">
#foreach($product as $p)
<div class="col-lg-3 text-center portfolio-item {{$p->category_id}} ">
<div class="card bg-transparent " style="width: 14rem;">
<img class="card-img-top" src="{{asset('front/')}}/assets/img/1.png" alt="Card image cap">
<div class="card-body">
<h5 class="card-title text-center">{{$p->title}}</h5>
<p class="card-text text-center">{{$p->description}}</p>
<p data-product-id="" style="color:#ff4a17;font-size: 20px ">{{$p->price}}</p>
<div class="btn-group">
<button type="button" class="btn btn-danger">Large</button>
<button type="button" class="btn btn-danger dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu">
<a data-product-id="{{$p->id}}" class="dropdown-item size-click" href="#">Large</a>
<a data-product-id="{{$p->id}}" class="dropdown-item size-click" href="#">Small</a>
</div>
</div>
</div>
</div>
</div>
</div>
JavaScript
The JavaScript (as it seems) has the following errors/issues that should be fixed:
Implicit global variables
As it stands, you try to grab the product ID from the clicked element and store it in a variable id (line 4). However, it looks as if that variable is an implicit global variable (hence it will be attached to the window object). You should use var id = ... instead of id = ....
Too much complexity
The same line has too much complexity. Why do you wrap the current element that has been clicked (this) into a jQuery collection if you immediately unwrap it (via [0])? Just write this.getAttribute( ... ) and you're done, no need for $(this)[0].getAttribute( ... ).
Oh, and if you follow my suggestion and use data- attributes, don't use getAttribute – use this.dataset.productId to get the ID and this.dataset.productId = ... to set it.
Invalid URL and/or useless interpolation
On line 8, you are passing an invalid URL to $.ajax( ... ). It seems you want to generate the correct URL with the help of a url( ... ) function and use string interpolation to pass the URL to the call to $.ajax. However, the url( ... ) function seems to already return a string that contains the URL. Therefor, it's unlikely that you need string interpolation at all. If I'm right, just use url: url('/getData'), and you are fine.
Useless call to getAttribute
The code in line 12 (success callback) makes a useless call to getAttribute. It's useless because the value returned by getAttribute isn't used anywhere. Also, getAttribute takes a single parameter, not two parameters. Did you mean setAttribute instead? If not, you can safely delete line 12. Otherwise, use setAttribute.
I'm not really sure that the code works correct, even if you use setAttribute. Let me explain: Calling $('p')[0] will give you the first paragraph/<p>-element of the whole page – probably not what you want. Instead, you want the first paragraph inside the corresponding .portfolio-item element. To do that, you have to pass a second argument to $( ... ) that marks the root element. Just save a reference to the .portfolio-item inside the click handler (but outside of the success callback) in a variable that you can then use later.
Wrong selector
Finally, in line 13 you pass the selector 'p[product-id="data.id"]' to the $( ... ) function. It seems you want to select the <p> element that has the product ID returned by the call to $.ajax. In that case, you have to generate a selector that contains the actual ID. Something like this:
`$('p[product-id="' + data.id + '"]')`
Although it seems you don't need any of this if you save the <p>-element you manipulated in line 12 into a variable. That's because the mentioned selector queries the DOM for exactly the same <p>-element. This means you can use the "native" .textContent property instead of jQuery's .text function.
Fixed JavaScript (with data-attributes)
Here is the complete JS code with most of the above mentioned issues gone.
$(function(){
$('.portfolio-item').on('click', '.size-click', function(){
var id = this.dataset.productId, // <-- uses data-attributes now
pitem = $(this).closest('.portfolio-item'); // <-- reference to containing portfolio-item element
$.ajax({
type: 'GET',
url: url('/getData'), // <-- fixed URL
data: { id: id },
success: function (data) {
console.log(data);
var p = $('p', pitem)[0]; // <-- get first paragraph in parent
p.dataset.productId = data.id; // <-- assign product id to data-attribute
p.textContent = data.priceS; // <-- display the price
}
})
})
});

How can I use jquery to append a div for me which also includes all of it's nested divs as well?

When a user creates a product, I want that product to be broadcasted to all other users and dynamically added to their screens. So far the broadcast aspect works amazingly.
But how can I dynamically add in this '.product' class, as well as all of a nested divs in an easy way? At the moment the only thing I can think of is copying and pasting all of it's divs in a jquery variable and adding it that way- there must be an easier way.
Here is where products are first loaded in when the page loads
<div class="product" id="{{$product->id}}">
<div class="product-image"><img src="/imgs/products/{{$product->type_id}}.png"></div>
<div class="product-content">
<div class="product-title" id="product-title">
{{ strtoupper(\App\ProductType::where('id', $product->type_id)->first()->name)}}
</div>
<div class="product-price">PRICE PER UNIT: <div class="price-value" id="price">{{$product->price}}</div> EXENS</div>
<br/>
QUANTITY: <div class="quantity-value" id="quantity">{{$product->quantity_available}}</div>
#if(strpos(\App\Group::where('id', $player->group_id)->first()->options, "\"showName\":true") !== false)
<br/>
SELLER: <div class="seller" id="seller">{{\App\User::where('id',$product->seller_id)->first()->name}}</div>
#endif
<br/>
PRICE: <div class="total-price" id="total-price">{{$product->price * $product->quantity_available}}</div>
<form class="buy-product-form" action="/UoE/buy-product/{{$product->id}}" method="POST">
{{csrf_field()}}
<button class="pull-right btn btn-primary">BUY NOW</button>
</form>
</div>
</div>
When the event is received the only way I can think of doing it as:
var productToAdd="<div class='buy-product-form'><div id='price'></div> " +
"" +
"" + //insert a massive string here containing all the other aforementioned sub-divs
"" + //And populate with json data
"" +
"</div>";
$('.content').append(productToAdd);
My solution was to take the entire code posted in the question and do make it as a one big HTML tag. That way my JS function can append the page with a HTML product div and it will already be bound with the necessary event listeners.

Problem trying to select next item in JQuery

I'm trying to select the next element to add the class image-radio-selected with JQuery.
My html is like
<div id="photocall">
#foreach ($photocalls as $photocall)
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
#endforeach
<input>
</div>
Im trying to:
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected'); // working
selected.next('.photocallThumb').addClass('image-radio-selected'); // not working
});
After 2 hours, trying to solve, reading doc,
I'm more confused than when I started...
what am I doing wrong?
One method is you will need to get out of the parent div, then do a next for the parent.
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected');
selected.parent(".d-inline-block").next(".d-inline-block").find('.photocallThumb').addClass('image-radio-selected'); // not working
});
.image-radio-selected{border:1px solid #ff00aa;}
.mx-1{width:100px;height:100px;border:1px solid #000000;}
.d-inline-block{display:inline-block;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="photocall">
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<button type="button" id="mybutton">next</button>
</div>
JQuery's next method selects the next sibling of the selected element. However, since your photocallThumb div is inside a d-inline-block div, it has no siblings. You'd have to go back up a level, then find the next photocallThumb, maybe something like selected.parent().find('.photocallThumb').eq(0).
However, an even better pattern that will help you avoid bugs like these is called templating. Basically, on the client side, you have an html template string, and you pass it data that represent your current state. In your case, you'd pass it an array of javascript objects, each one with an image url and an isSelected boolean. Then, when your state changes, instead of using jquery to try to fix what's changed, you just rerender your template and replace your html element's content with the newly rendered template, and it's now magically in the correct state. This is the pattern favored by large frameworks like React and Angular.
Here's an example from lodash that renders a list of usernames:
// Use the "evaluate" delimiter to execute JavaScript and generate HTML.
var compiled = _.template(
`<% _.forEach(users, function(user) { %>
<li><%- user %></li>
<% }); %>`);
compiled({ 'users': ['fred', 'barney'] });
// => '<li>fred</li><li>barney</li>'

Template won't append, but other things will

I am really stumped by this one. I have a template which contains data. I alert the variable containing this rendered template to prove it contains the data. I have tried using html() innerHTML() and others to then convert it before appending it. Using identical jquery syntax, I am able to append a div exactly as I desire, except with different contents.
success: function (data) {
if (data['success'] == 1) {
$.get('templates/PostReply.mustache', function(file){
var newPostArray={"reply_body":bodyText,
"replier_username": "<?php echo $sess_username; ?>",
"replier_profimg0": '<?php echo $sess_profimg0; ?>'
};
var html = Mustache.render(file, newPostArray);
$('#new-posts-container').append(html);
alert(html);
$(form).closest('#reply-divy').nextAll('#new-posts-container').append('<div>hello</div>');
//this works
$(form).closest('#reply-divy').nextAll('#new-posts-container').append(html);
// this does not work
e.preventDefault();
});
// You could also use the data['message'] that got sent back here.
}
},
So for some reason, the contents are unable to append. I am not receiving any errors.
This is what html looks like in an alert:
<div class="reply-div">
<div class="pull-left feed-entity-side-img">
<a href="profilepage.php?username=cb_snn">
<img src="photos/user_photos/public/2015/02/12/04/1ded2487680.jpg" alt="User" class="media-object no-padding reply-side-img"/>
</a>
</div>
<div class="media-body" style="padding-bottom:5px;">
<span class="pull-right" style=""> </span>
<span ><b>co_byrne</b></span>
<p> dgsadgasdgasdgasdgasdgasdgs
</p>
</div>
</div>

More effective way to append json data with jQuery & Laravel

I am building a twitter style feed with Laravel and jQuery.
My problem is that I'm sure I built this logic up badly.
So I have an included view what shows the tweet results.
Sending the data is just a basic ajax post with some DOM manipulation that's fine too.
After the form is submitted I display the fresh tweet with and append.
But the problem is no matter how i build my logic up, i always end up with duplication.
So what I do
Send the form, and the success function appends the data to the view
success: function(data) {
if(data.status === "success") {
$('#tweet-textarea').val("");
$('#tweets-wrapper').prepend(data.content);
}
},
And returning the goes the following way. After the tweet is saved, I return it in an array what I encode to json
$data = array('status' => 'success', 'content' =>
'<div class="tweet-box">
<div class="media">
<a class="pull-left" href="#">
<img src="http://placehold.it/60x60" alt="">
</a>
<div class="media-body">
<h4 class="media-heading">
'. $this->tweet->user->metadata->full_name .'
<small>'. "#".$this->tweet->user->username .'</small>
<small>'. $this->tweet->created_at .'</small>
</h4>
'. $this->tweet->message .'
</div>
</div>
</div>');
I know not the best way, and my problem is actually in my controller I am duplicating code, because the returned result "content in array" is the same just like in my view, so if I make any modification I need to make both
So is there a more effective way to do this?
You can use jQuery jPut Plugin to append json easily
<div jput="template">
<div class="tweet-box">
<div class="media">
<a class="pull-left" href="#">
<img src="http://placehold.it/60x60" alt="">
</a>
<div class="media-body">
<h4 class="media-heading">{{}}</h4>
</div>
</div>
</div>
</div>
<div id="main">
</div>
<script>
$(document).ready(function(){
//main is the div that you want to append
$('#main').jPut({
ajax_url:'domain.com/data.json', //your json data page
name:'template' //jPut template name
});
});
</script>
And in you json page no need to send all the div
$data = array('status' => 'success', 'content' => $this->tweet->user->metadata->full_name);
If you want to remove duplication of code, you are going to have to take all that logic out of your view and just pass it a nice long string for the entire section from your controller.
I'd start with making a function which can take a full name, username, timestamp, and message and create the tweet.
public function createTweet($fullName, $username, $created_at, $message)
{
return '<div class="tweet-box">
<div class="media">
<a class="pull-left" href="#">
<img src="http://placehold.it/60x60" alt="">
</a>
<div class="media-body">
<h4 class="media-heading">
'. $full_name .'
<small>'. "#".$username .'</small>
<small>'. $created_at .'</small>
</h4>
'. $message .'
</div>
</div>
</div>';
}
Then when you are looping through your tweets, call this function each time through and keep concatenating the response in a string, then you can just pass the string to your view and echo it there.
On your function which is returning ajax, do the same...
return Respons::json(array(
'status' => 'success',
'content' => $this->createTweet($this->tweet->user->metadata->full_name, $this->tweet->user->username, $this->tweet->created_at, $this->tweet->message)
));
You could also take a lot at HTML::macro() as well if you find yourself needing this functionality across your entire app. http://laravel-recipes.com/recipes/181 for a nice and quick HTML::macro() tut.

Categories