More effective way to append json data with jQuery & Laravel - javascript

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.

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
}
})
})
});

Display content based on id (from database, not html id)

Here is what I want to do. I have the following html displaying projects from by db.
<div class="col-md-5">
<ul class="todo-projects-container">
<li class="todo-padding-b-0">
<div class="todo-head">
<button class="btn btn-square btn-sm green todo-bold">Add Project</button>
<h3>Projects</h3>
<p>4 Waiting Attention</p>
</div>
</li>
<?php foreach ($projects as $project): ?>
<li class="todo-projects-item">
<h3><?php echo $project->project_name ?></h3>
<p><?php echo $project->project_body ?></p>
<div class="todo-project-item-foot">
<p class="todo-red todo-inline">Project #<?php echo $project->project_id ?></p>
<p class="todo-inline todo-float-r">32 Members
<a class="todo-add-button" href="#todo-members-modal" data-toggle="modal">+</a>
</p>
</div>
</li>
<div class="todo-projects-divider"></div>
<?php endforeach; ?>
</ul>
</div>
When I first load the page, the first project receives the class="active" (using jquery) and whenever a click a project it removes the active class from the previous li and adds to the clicked one. So far so good.
Now I need to display the following:
<ul class="todo-tasks-content">
<li class="todo-tasks-item">
<h4 class="todo-inline">
<a data-toggle="modal" href="#todo-task-modal">Welcome to the hotel California</a>
</h4>
<p class="todo-inline todo-float-r">Bob,
<span class="todo-red">TODAY</span>
</p>
</li>
<li class="todo-tasks-item">
<h4 class="todo-inline">
<a data-toggle="modal" href="#todo-task-modal">Talking 'bout my generation</a>
</h4>
<p class="todo-inline todo-float-r">Shane,
<span class="todo-red">TODAY</span>
</p>
</li>
</ul>
On the above html all the info is obviously static. I know how to make ajax calls to fetch info from my db. What I don't really know how to do is displaying the corresponding tasks according to project_id whenever I click on a project.
I assume I need to make an ajax call and return the data along with some html and then do something like (dummy syntax)
onclick(function() {
var tasksHTML = insert ajax call here
});
Not sure if this is the right approach, I'm new to js. Any suggestions?
UPDATE:
Here is a picture:
In the picture, there is an active (clicked) project and on the right are the tasks that have that project id. How do I change the tasks list when I click a project?
First we need to give javascript a way to get the id so it can pass it to the PHP file that gets the tasks.
I assume you're binding JQuery click to the <li> so also include a data attribute and call it projectid. Or add this data attribute wherever the click method is bound.
<?php foreach ($projects as $project): ?>
<li class="todo-projects-item" data-projectid="$project['id']">
//.................
<?php endforeach; ?>
If you are using JQuery do this in your .click method
$('.todo-projects-item').click(function(){
//Get your project id from the data-attribute
projectId = $(this).data('projectid');
//run your ajax
$.post('phpfile.php', {projectId:projectId}, function(r){
//your phpfile.php should echo a json of the tasks
//see example below
$('.class-of-the-task-div').html(r.html);
}, 'JSON');
});
your php file can be something like this
$r['html'] = '<ul class="todo-tasks-content">
<li class="todo-tasks-item">
//....................Stuff
</li>
</ul>';
echo json_encode($r);

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>

How to call a ASP function from onclick in the HTML?

I have 3 link in my HTML. When I click one of these a variable in the session must change.
How can I do that?
<div id="eng">
<a href="#" onClick="setLanguage('en')";>
<img id="eng_img" src="bandiera01.png" />
</a>
</div>
<div id="rus">
<a href="#" onclick="setLanguage('ru');">
<img id="rus_img" src="bandiera02.png" />
</a>
</div>
<div id="ted">
<a href="#" onclick="setLanguage('de');">
<img id="ted_img" src="bandiera03.png" />
</a>
</div>
setLanguage(txt) is a JavaScript function but I want to use it in ASP to save it in session.
You need send the information to server, you can post by a normal link or send by ajax. I think with in this case, is better you send by normal link, for example:
<div id="eng">
<a href="ChangeLanguage.asp?language=en">
<img id="eng_img" src="bandiera01.png" /></a>
</a>
</div>
<div id="rus">
<a href="ChangeLanguage.asp?language=ru">
<img id="rus_img" src="bandiera02.png" />
</a>
</div>
<div id="ted">
<a href="ChangeLanguage.asp?language=de">
<img id="ted_img" src="bandiera03.png" />
</a>
</div>
In the page of destination, you get the "language" information of the link.
You can address this issue in a couple of way:
Turn your links into submit buttons, put them inside a form, submit the page server side to manage the language change business logic. This is a classic asp approach. You have to rebuild the page server side.
Let the setLanguage() fire an ajax call to an asp page that retrieves the localized resources. On success, the resources are mapped into the corresponding elements of the DOM: maybe set this logic into a different function:
HTML
<div class="lang">
en
</div>
<div class="lang">
ru
</div>
<div class="lang">
de
</div>
SCRIPT
(function($){
window.setLanguage = function(langCode){
$.ajax({
type: "GET",
url: "myLanguageHandler.asp",
data: { "languageCode": languageCode },
async: true,
error: function (req, status, message) {
//manage the error
},
success: function (data) {
mapPage(data);
}
});
/*
* for demo purpose only
* console.log('Set language: ' + langCode);
*/
};
$('.lang a').bind('click', function(e){
window.setLanguage($(e.target).attr('data-lang'));
return false;
});
})(jQuery)

Javascript + jquery issue

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.

Categories