Send order of jQuery sortable to Laravel controller - javascript

I have a collection of Article objects that have a public attribute int priority. This field ist used to display the articles in the intended order. However, I'd like to be able to rearrange the order of the articles in the admin area.
I included jQuery and with this Laravel/Blade snippet
<ul class="selectable-demo-list" id="sortable-list-basic">
#FOREACH($articles as $article)
<li> {{ $article->label}} </li>
#ENDFOREACH
</ul>
I can produce this HTML output:
<ul class="selectable-demo-list" id="sortable-list-basic">
<li> My article (ID: 1) </li>
<li> Another article (ID: 2) </li>
<li> ... </li>
</ul>
I can access the respective priority via $article->priority and their unique IDs via $article->id if these elements should be included in the code.
The <ul> posted above is rendered correctly: All <li> elements are displayed as sortable jQuery elements. If I drag an item to a certain position, it stays there for the time being.
Unfortunately, I have no idea how to save the new order (= update the items priorities according to the list positions).
This shouldn't be done directly. Instead, I want to use an update button. Maybe I can use a form and send an array like this to my controller:
$priorities = [1=>3; 2=>1; 3=>2] // ID => new priority
Is this possible? Or should I use a different approach? Any help is greatly appreciated!

Add id with each of your li like id="id-{{ $article['id'] }}"
You can call an ajax request when you are changing any order using this sortable plugin like below code
$("#sortable-list-basic").sortable({
update: function (e, u) {
var data = $(this).sortable('serialize');
$.ajax({
url: "{{ url('controller/sorting_method') }}",
type: 'post',
data: data,
success: function (result) {
},
complete: function () {
}
});
}
});
Then inside your method, take your new order for each item & save it to database such as
$ids = $request->id;
foreach($ids as $order => $id){
$article = Article::findOrFail($id);
$article->order = $order;
$article->save();
}

Related

Passing data from MVC controller to jsTree through ajax calls.

I have a jsTree with a parent node and 5 children nodes. They function fine. I am trying to implement a dynamic jsTree where with click of a node, an ajax call should pass that node's ID to my java MVC spring-boot controller and a Map with keys as child nodes' IDs and value as names of child nodes.
So far I have managed to get the value of the clicked child node's ID and pass it to my java controller through ajax call. But I'm not able to proceed further as I am not sure how to structure the data that is passed from controller to ajax call which in turn has to implement the jsTree.
Here's the code of my existing jsTree -
<div id="container">
<ul>
<li id = "id1">Root
<ul>
<li id="id 1-1">child 1</li>
<li id="id 1-2">child 2</li>
<li id="id 1-3">child 3</li>
<li id="id 1-4">child 4</li>
<li id="id 1-5">child 5</li>
</ul>
</li>
</ul>
</div>
Here's the code of my ajax -jquery call that passes the nodeID to the controller-
$(function() {
$('#container').on('changed.jstree', function (e, data) {
var i, j, r = [], rid = [];
for(i = 0, j = data.selected.length; i < j; i++) {
r.push(data.instance.get_node(data.selected[i]).text);
rid.push(data.instance.get_node(data.selected[i]).id);
}
console.clear();
console.log('Selected: ' + r.join(', '));
console.log('Selected id: ' + rid.join(', '));
$.ajax({
type: 'GET',
url: "http://localhost:8080/tree/object?nodeID="+rid.join(', '),
contentType: 'text/plain',
crossDomain: false,
async:true,
success:function() {
}
});
})
.jstree();
});
I'm limited by my knowledge of jsTree, ajax and jquery. Any help would be appreciated. I am looking into the documentation of jsTree: filling the tree through ajax calls here.
You don't want to do your own AJAX call - You can set a URL to use as per: https://www.jstree.com/api/#/?f=$.jstree.defaults.core.data and JSTree will perform the Ajax calls for you.
set the url property to your url, and data to a function that returns the node id;
'url' : 'ajax_nodes.html',
'data' : function (node) {
return { 'id' : node.id };
}
If returning the data from an Ajax call - you should probably return it in JSON instead, not in HTML.
So this page is what you should be looking at: https://www.jstree.com/docs/json/
The minimum you need is a JSON object like so;
{
id : "string" // will be autogenerated if omitted
text : "string"
children : false
}
Where Children should be true if that node can expand and trigger another all with itself as the ID passed to get its children and false if it is a leaf node.

load part of the html page when filtering results with ajax

I want to filter a search results using 3 checkboxs. The results are presented in the div with the id=posts_results
<div class="checkbox">
<label><input type="checkbox" id="id1" class="typePost" value="En groupe"> val1 </label>
</div>
<div class="checkbox">
<label><input type="checkbox" id="id2" class="typePost" value="En groupe"> val2 </label>
</div>
<div class="checkbox">
<label><input type="checkbox" id="id3" class="typePost" value="A domicile"> val3</label>
</div>
<div class="checkbox">
<label><input type="checkbox" id="id4" class="typePost" value="Par webcam"> val4</label>
</div>
<div id="posts_results">
{% include 'posts/posts_results.html' %}
</div>
<script>
$('.typePost').change(function (request, response) {
var v1=$('#id1').is(":checked")? 1:0;
var V2=$('#id2').is(":checked")? 1:0;
var V3=$('#id3').is(":checked")? 1:0;
var v4=$('#id4').is(":checked")? 1:0;
$.ajax({
url: '/posts/type_lesson/',
dataType: 'json',
type: "GET",
data: {
group: groupChecked,
webcam: webcamChecked,
home: homeChecked,
move: moveChecked,
distance: distance,
},
success: function (object_list) {
$('#posts_results').load("my_page.html", object_list);
alert('after')
}
});
});
<script>
this is my url:
url(r'^filter/$', views.filter, name='filter_type_lesson'),
and this is my view:
def filter(request):
if request.method=='GET':
#as an exemple I'll send all posts
data= PostFullSerializer(Post.objects.all(), many=True)
return JsonResponse(data.data, safe=False)
The filter function excute some filters according to the json sent data, serialize the filtered posts and send them back (in this case I send all the posts as an example).
The results are displayed using a forloop in the div with id "posts_results" and the html is in the file posts_results.html.
The json data are sent but the ajax success function does not update or load the div
and it is also possible to stay
I like to stay away from raw POST data as much as possible and let the forms API do the heavy lifting. You can do what you have already with a lot less code in a much more secure way.
Make a form with four BooleanFields named for the BooleanFields in your model. You can override how they are displayed in the HTML with the label variable.
class TheForm(forms.Form):
my_field = forms.BooleanField(required=False, label="What I want it to say")
my_field2 = forms.BooleanField(required=False, label="What I want it to say 2", help_text="Something else")
my_field3 = forms.BooleanField(required=False, label="What I want it to say 3", help_text="Something else")
Output as <form class="my_form">{% csrf_token %}{{form.as_table}}</form>
Submit it with JS like this:
$('.my_form input[type=checkbox]').change(function(e){
e.preventDefault()
$.post('module/filer/', $('.my_form').serialize(), function(data) {
// Handle data
});
});
When the form is submitted and validated take the cleaned_data attribute and filter your models like this
models = Post.objets.filter(**form.cleaned_data)
This will work because the form fields and named the same as the fields in your model. The same as doing Post.objects.filter(my_field=True, my_field2=True, my_field3=False). Then you can do whatever you want with it. I would use a FormView to do all this:
class MyView(FormView):
form_class = TheForm
def form_valid(self, form):
models = Post.objets.filter(**form.cleaned_data)
data= PostFullSerializer(data, many=True)
return JsonResponse(data.data, safe=False)
Now nothing is going to update the div by itself. It is only created when the HTML is initially requested. In your success function you'll need to append your elements manually like this:
$('.my_form input[type=checkbox]').change(function(e){
e.preventDefault()
$.post('module/filer/', $('.my_form').serialize(), function(data) {
var post_results = $('#post_results').html(''); // Clear out old html
$.each(data, function(item) {
// Create new divs from ajax data and append it to main div
var div = $('<div>');
div.append($('<div>').html(item.my_field));
div.append($('<div>').html(item.my_field2).addClass('something'));
div.appendTo(post_results);
});
});
});
You can also just past rendered HTML through ajax and do $('#post_results').html(data);. Instead of calling json response you would call self.render_to_response on the FormView.
maybe you could try to render the template in your view and then load the rendered data in your div.
Supposing your posts/posts_results.html is some as:
<ul>
{% for post in posts %}
<li> Post: {{post.name }} / Author: {{post.author}} / Date: {{post.created_at}}</li>
{% endid %}
<ul>
In your view, at the moment when you do respective actions, you can render the template and add the html content to the response, ie (based un your current code):
def filter(request):
if request.method=='GET':
json_data = {
"success": False,
"message": "Some message",
"result": "some result",
}
posts = Post.object.all()
template = "posts/posts_results.html"
things_to_render_in_your_template = {
"posts": posts, # you can add other objects that you need to render in your template
}
my_html = get_template(template)
html_content = my_html.render(things_to_render_in_your_template)
# here the html content rendered is added to your response
json_data["html_content"] = html_content
json_data["success"] = True
return JsonResponse(json_data)
Then in your JS, at the momento to check ajsx response, you can add the rendered content into your div
$.ajax({
url: '/posts/type_lesson/',
dataType: 'json',
type: "GET",
data: {
group: groupChecked,
webcam: webcamChecked,
home: homeChecked,
move: moveChecked,
distance: distance,
},
success: function (response) {
# response is the json returned from the view, each key defined in your json_data dict in the view, is a key here too
# now insert the rendered content in the div
$('#posts_results').html(response["html_content"]);
alert('after');
}
});
I suggest you instead of create one by one data to your ajax request, use serialize method of jquery or create a FormData object, also instead of GET, use POST to do your request more safe

Vue.js: How to map a list of keys to Firebase objects?

I develop a small web-app based on Vue.js using Firebase to store and sync the data. I store items (e.g. with attributes title and subtitle) and lists with an attribute listitems, where an array of keys (those generated from Firebase) of items is stored. The structure looks like this:
Now the problem: I want to display a list and show the items from the listitems attribute and I'm doing it like this:
Compontent:
var ShowList = Vue.extend({
template: '#show-list',
firebase: {
// get all existing items from firebase
items: firebase.database().ref('items')
},
data: function () {
// get list item keys of list 'list_id' and bind it to this.list
this.$bindAsObject('list', listsRef.child(this.$route.params.list_id));
return {
list: this.list
};
}
});
Template:
<!-- show a list -->
<template id="show-list">
<ul v-if="list.items != ''">
<li v-for="key in list.items"> <!-- I would like to not being forced to -->
<template v-for="item in items"> <!-- iterate the whole list of existing items -->
<span v-if="item['.key'] == key">
{{ item.title }}
</span>
</template>
</li>
</ul>
<div v-else>No items.</div>
</template>
As you can see, I have to use two iterations where I iterate the full items list for every entry in list.items.
My question: Is there a more efficient way to map the actual objects to the list of object keys? For a huge number of item records, my approach will be very slow. Maybe I'm just too blind to see a simpler solution?
Thanks for your time!
I think you have to denormalize/duplicate some data there. I had a similar situation and this Firebase video cleared a lot of things up for me: https://youtu.be/ran_Ylug7AE?t=2m22s (Link updated to passage at 2:22. The whole serie is worth watching btw.)
My shot at it would be adding (Firebase) keys in "listitems", just like you have done in "items", with only the most crucial data there, so that you can link to a full description
Is your data read only? In which case you could move the filter logic from your template to your data module, like so (I expect I have unintended side-effects):
data: function () {
// get list item keys of list 'list_id' and bind it to this.list
this.$bindAsObject('list', listsRef.child(this.$route.params.list_id));
var items = firebase.database().ref('items')
var activeItems = this.list.items.map(function(key) {
return items[key]
})
return {
activeItems: activeItems;
};
}

Fetching with PHP, using with Javascript

I'm currently facing a problem and i would like your assistance to solve it the right way. Two languages.. depending on it's other. (At least in my case).
PHP: access database, insert, select data.
Javascript: useful calling events without having to refresh my page.
Well.. i've used ajax, but my way seems quite complicated to be correct.
Let me use an example. Let's say that i have the following PHP function.
function createDiv($value1, $value2, $value3){
echo "
<div>
<h3>."$value1".</h3>
<h3>."$value2".</h3>
<h3>".$value3."</h3>
</div>
";
}
My inside my HTML i'm calling this function like this.
<?php
$values = $db->getValues(); //( Let's say that i'm getting an array )
createDiv($values[0],$values[1],$values[2]);
?>
Now lets go a step further... I want to append data inside this div when clicking on a predefined list item without having to refresh.
<ul class="social-buttons" id="demo2">
<li>
<a onclick="letterSearch(this);" >A</a>
</li>
<li>
<a onclick="letterSearch(this);" >B</a>
</li>
<li>
<a onclick="letterSearch(this);" >C</a>
</li>
<li>
So, now i'm using javascript & ajax.
function letterSearch(element){
//With this ajax i'm calling a similar function to $db->getValues();
//That i called before to get my values
//With the difference of the searching parameter
$.ajax ({
type:"POST",
url: "ajaxAccess.php",
dataType:"json",
data: {tag: 'valuesWithSearch', arguments: element.innerHTML},
success: function(result) {
var jsonValues = JSON.parse(result);
//After this point i have stored in jsonValues the expected array list that i wanted to get.
//Now what??
}
});
}
So..
My first question is: how can i put the data i just got from ajax at the bottom of my div?
jQuery.append()?
And last but not the least.. Is my approach overcomplicated? Is there any other way?
IN PHP
<?php
echo json_encode(["values"=>$db->getValues()); //Let's say this is an array
?>
IN HTML
<ul class="social-buttons" id="demo2">
<li>
<a class="letter-search" >A</a>
</li>
<li>
<a class="letter-search" >B</a>
</li>
<li>
<a class="letter-search" >C</a>
</li>
<li>
IN JAVASCRIPT/JQuery
$(".letter-search").click(function(e){
e.preventDefault();//Prevent default link action
letterSearch($(this));
})
function letterSearch(element){
$.ajax ({
type:"POST",
url: "ajaxAccess.php",
dataType:"json",
data: {tag: 'valuesWithSearch', arguments: element.text()},
success: function(result) {
var response = JSON.parse(result);
//You now have a valid JSON response
//Append if needed, or loop through and process before appending
element.append(response.values)
}
});
}

How to make hash-tags with meteorjs and iron:router?

Im trying to make hash-tags support with iron:router.
Now I have data of posts, each post has an array of tags, which renders as a list of links.
<ul class="list-unstyled list-inline">
{{#each tags}}
<li>
<a class="tag" href="{{pathFor 'postsTag'}}">{{this}}</a>
</li>
{{/each}}
</ul>
But I cannot understand how to get the value of a tag on click and to render posts according to this specific hash-tag.
I can get the value of a tag by Session on click
Template.post.events({
"click .tag": function(e) {
Session.set('tag',this.toString());
return false;
}
});
But i cannot make dynamic router on it.I tried something like that
Router.route('/posts/:tag',{
name: 'postsTag',
data: function() {
return Posts.find({tags:{$in: value_of_tag }});
}
});
If tags is a simple array of strings, you can query this field to match a particular value using this syntax :
Posts.find({
tags: "value"
});
$in is used when you want to search for documents having a particular field value among a set of values defined in an array.
Posts.find({
tags: {
$in: ["value1","value2","value3"]
}
});
This query would return posts having a tags array containing at least one of the specified value, which would be useful if you want to filter posts using multiple tag values.
http://docs.mongodb.org/manual/reference/operator/query/in/#op._S_in
If you want to define a route displaying only posts having a particular tag value, use this controller :
Router.route("/posts/:tag", {
name: "postList",
waitOn:function(){
return Meteor.subscribe("postsByTag",this.params.tag);
},
data: function() {
return Posts.find({
tags:this.params.tag
});
}
});

Categories

Resources