Convert php array to javascript array with select2 - javascript

I have the following php array in a laravel variable called $salaries which is passed to a blade view:
array:4 [▼
2 => "£8, Per hour"
3 => "£10, Per hour"
23 => "Up to £10000, Per annum"
24 => "£10,000 - £15,000, Per annum"
]
In my blade view I have a drop which when changed, I want to load a select2 dropdown with the above options. Below is my code:
$(document).on("change", ".js-selector", function() {
var options = {!! json_encode($salaries) !!};
$("#salary_list").empty().select2({
data: options
});
})
However nothing is getting loaded into the dropdown. So I've narrowed it down to the options data for select2 not being in the correct format.
When I output options variable to console I'm getting the following object as opposed to a javascript array?
{2: "£8, Per hour", 3: "£10, Per hour", 23: "Up to £10000, Per annum", 24: "£10,000 - £15,000, Per annum"}
How do I transform the options into correct format for the select2 data?

You have to transform your data to the correct format, here you can see the correct data format:
var data = [
{
id: 2,
text: '£8, Per hour'
},
{
id: 3,
text: '£10, Per hour'
}
];
You could pass the array in the correct format to the view, something like:
$salaries = \App\Models\Salary::all(); // eloquent collection
$salaries = $salaries->map(function ($salary) {
return ['id' => $salary->id, 'text' => $salary->text];
})->toArray();
It would give result in something like this:
array:1 [▼
0 => array:2 [▼
"id" => 2
"text" => "£8, Per hour"
]
0 => array:2 [▼
"id" => 3
"text" => "£10, Per hour"
]
]
Or you can transform the array in javascript, the Select2 documentation explains here how you can transform your data:
Select2 requires that the id property is used to uniquely identify the
options that are displayed in the results list. If you use a property
other than id (like pk) to uniquely identify an option, you need to
map your old property to id before passing it to Select2.
If you cannot do this on your server or you are in a situation where
the API cannot be changed, you can do this in JavaScript before
passing it to Select2:
var data = $.map(yourArrayData, function (obj) {
obj.id = obj.id || obj.pk; // replace pk with your identifier
return obj;
});
In your case it would be something like this:
$(document).on("change", ".js-selector", function() {
var options = {!! json_encode($salaries) !!};
var data = $.map(options, function (value, key) {
return {id: key, text: value};
});
$("#salary_list").empty().select2({
data: data
});
})

exactly as Serhii said, simply extract the values from you associative array before encoding it:
$(document).on("change", ".js-selector", function() {
var options = {!! json_encode(array_values($salaries)) !!};
$("#salary_list").empty().select2({
data: options
});
})

Your array must have the structure like this:
[
[
'id' => 2,
'text' => "£8, Per hour"
],
[
'id' => 3,
'text' => "£10, Per hour"
],
[
'id' => 23,
'text' => "Up to £10000, Per annum"
],
[
'id' => 24,
'text' => "£10,000 - £15,000, Per annum"
],
]
https://select2.org/data-sources/arrays

Related

Laravel update all users age by x

I want to update all users in my database with an age value which I get from my request.
How do I manage this?
I somehow need the current value in the db and multiple it.
DB::table('customers')
->update([
'age' => DB::raw('column1 * 2'),
]);
Let's assume that the name of the field in your $request is multiple, you can iterate over your customer records and update each of them, applying your multiple value to their age:
// grab the `multiple` value from your request
$multiple = $request->get('multiple');
// get all your customers, loop over them and update each record
Customer::all()->each(function ($customer) use ($multiple) {
$customer->update(['age' => $customer->age * $multiple]);
});
If you want to use the QueryBuilder rather than Eloquent, then you can do the following:
DB::table('customers')->get()->each(function ($customer) use ($multiple) {
DB::table('customers')
->where('id', $customer->id)
->update(['age' => $customer->age * $multiple]);
});
Maybe you want to update a column based on a value as an input that is provided by the user.
Also notice I have used double quotation.
DB::table('your_table')
->where('some_column', $someValue)
->update(array(
'column1' => DB::raw("column1 * $your_input_variable")
));
To avoid the N+1 problem, I will advise you use the Eloquent's "WhereIn" method. The idea is that you build the list of items to update within the logic instead of hitting the db server N no of times in a loop as others suggested.
$itemTypes = [1, 2, 3, 4, 5]; //loop through your request payload and make this list.
$columns = [[
'name' => 'Ezugudor',
'age' => '18',
'rank' => 13
],[
'name' => 'Mathew',
'age' => '13',
'rank' => 1
]]; //loop through your request payload and make this list.
ItemTable::whereIn('item_id', $itemTypes)
->update($columns);
A cleaner way to do that
$items = Model::all();
$insertData = collect();
foreach ($items as $item)
{
$insertData->push([
'id' => $item['id'],
'otherstuff' => $item['name']),
'age' => $item['age'] * 2,
'more other stuff' => $item['itmPrice'],
]);
}
// chunks of 1000 insert into db
foreach ($insertData->chunk(1000) as $chunk)
{
DB::table('table_name')
->upsert(
$chunk->toArray(), // array of data that is going to be inserted or updated
['id'], // array of the column names that should be used for finding the updatable row
[ 'age'] // values that will be updated
);
}
upsert docs here

Vue Js v-model not working with array created in Laravel model

I'm currently in the process of building a CMS using Laravel and Vue JS which build forms dynamically based on an array of data created in the Laravel model. Here is an example:
class TheBuilding extends Model
{
protected $fillable = [...];
public function formFields(){
$fields = [
[
'label' => 'Title',
'name' => 'title',
'component' => 'input_text'
],
[
'label' => 'Content',
'name' => 'content',
'component' => 'input_textarea'
],
[
'label' => 'Main Image',
'name' => 'main_image',
'component' => 'input_single_upload'
],
[
'label' => 'Gallery',
'name' => 'gallery',
'component' => 'input_multiple_upload',
'meta' => [
[
'type' => 'text',
'name' => 'caption',
'label' => 'Caption'
]
]
],
];
return $fields;
}
}
Basically this array gets passed into Vue JS and parsed to dynamically display Vue JS form components accordingly. This has been working great but I've come across an interesting issue with the Gallery multiple upload component which needs the ability to assign captions to images.
To fast forward a bit, I'm at the point where I have an array of uploaded files which get iterated through and displayed on the page, and then I have the input textfield for the caption underneath.
Here's my component (edited to show the relevant bits):
<template>
<div class="row">
<div v-for="(file, i) in files">
<img :src="file.file" >
<div v-for="meta in file.meta">
<input v-if="meta.type == 'text'" type="text" v-model="meta.value">
</div>
</div>
</div>
</template>
<script>
export default{
computed:{
files(){
let uploads = [];
/*this.uploaded is just an array of filenames*/
this.uploaded.forEach((file, i) => {
let createdMeta = [
{
name:"caption",
type:"text",
value:''
}
];
uploads.push({file,meta:createdMeta});
});
return uploads;
}
},
props:{ ... },
mounted(){
//CODE THAT HANDLES DROPZONE UPLOAD
},
name: 'InputMultipleUpload',
data(){
return {
showUploadProgress:true,
}
}
}
</script>
The bit I'm focusing on is:
let createdMeta = [{
name:"caption",
type:"text",
value:''
}];
You'll notice here that I've created that array statically. If I do that, when I type in a caption textbox everything works fine and the caption value gets updated dynamically by v-model as expected. Essentially, I get the desired result and everything is good.
However, if I try and set this this dynamically from the created model ie:
let createdMeta = formFields;
where formFields is the reference to the model array, when I then type in the textbox it updates all other textboxes and values in the files array created. V-Model no longer seems to relate to the specific textbox.
So I guess the question I'm asking is:
a) Why is it behaving that way when I passed in the referenced array
b) Why does it work fine if I just manually create that array?
c) How can I get A to behave like B?
Thanks everyone, happy to clarify anything. I assume i'm missing a piece in the reactivity puzzle.
Cheers,
Lew
You should be using data not computed.
Try something like this:
<script>
export default {
props: {...},
mounted () {
//CODE THAT HANDLES DROPZONE UPLOAD
// 2. handlers should call `onUpload`
},
name: 'InputMultipleUpload',
data () {
return {
files: [], // 1. declaring `files` here makes it reactive
showUploadProgress: true,
}
},
methods: {
onUpload (file) {
const meta = createdMeta = [{
name: "caption",
type: "text",
value: ''
}]
this.files.push({file, meta}); // 3. push the new data onto the stack and the component will update
}
}
}
</script>
With this:
let createdMeta = formFields;
uploads.push({file,meta:createdMeta});
in a loop you actually just pass the reference to the same formFields array object and then binds all your inputs to it.
This is likely to work as it should, if you pass a new array copy for each input. You can do it easy this way:
let createdMeta = formFields.slice();
let createdMeta = JSON.parse(JSON.stringify(formFields))
Thanks to Rick in Slack, and Dave Steward too, I have refactoring to do but for the purpose of this thread here is the solution

Jquery Autocomplete showing an empty list

Edit 2 : even better, multiple values works
Actually, one simply has to give a "value" field that fills the box. No need for the "id/label" field, but value field is required. This is working :
foreach ($queries as $query)
{
$results[] = [
'zip' => $query->zip,
'value' => $query->commune,
'libelle' => $query->libelle,
'lieudit' => $query->lieudit
];
}
return Response::json($results);
Edit : here is the solution, thanks to Adyson's answer
The script should be json formatted and returning
An array of objects with label and value properties:
[ { label: "Choice1", value: "value1" }, ... ]
(jQuery API documentation)
So, modifying the PHP script like this will work :
foreach ($queries as $query)
{
$results[] = [
'id' => $query->zip,
'value' => $query->commune,
];
}
return Response::json($results);
Original question
Using Jquery Autocomplete, querying a script.
The list shows as many rows as there are results (when I set my script to return X results, there are X rows as well in the list) :
But it doesn't fill the rows with the data. What could have gone wrong there ?
The data returned is some json :
Request URL:http://localhost:8000/search/autocomplete?term=750
Request Method:GET
Status Code:200 OK
Remote Address:127.0.0.1:8000
Response Headers
view source
Cache-Control:no-cache
Connection:close
Content-Type:application/json
Date:Tue, 15 Nov 2016 14:53:07 GMT
Host:localhost:8000
And here is the data :
[{"zip":"75004","commune":"PARIS 04","libelle":"PARIS","lieudit":""},
{"zip":"75005","commune":"PARIS 05","libelle":"PARIS","lieudit":""},
{"zip":"75003","commune":"PARIS 03","libelle":"PARIS","lieudit":""},
{"zip":"75006","commune":"PARIS 06","libelle":"PARIS","lieudit":""},
{"zip":"75008","commune":"PARIS 08","libelle":"PARIS","lieudit":""},
{"zip":"75012","commune":"PARIS 12","libelle":"PARIS","lieudit":""},
{"zip":"75015","commune":"PARIS 15","libelle":"PARIS","lieudit":""},
{"zip":"75016","commune":"PARIS 16","libelle":"PARIS","lieudit":""},
{"zip":"75017","commune":"PARIS 17","libelle":"PARIS","lieudit":""},
{"zip":"75010","commune":"PARIS 10","libelle":"PARIS","lieudit":""},
{"zip":"75018","commune":"PARIS 18","libelle":"PARIS","lieudit":""},
{"zip":"75001","commune":"PARIS 01","libelle":"PARIS","lieudit":""},
{"zip":"75009","commune":"PARIS 09","libelle":"PARIS","lieudit":""},
{"zip":"75014","commune":"PARIS 14","libelle":"PARIS","lieudit":""},
{"zip":"75002","commune":"PARIS 02","libelle":"PARIS","lieudit":""},
{"zip":"75007","commune":"PARIS 07","libelle":"PARIS","lieudit":""},
{"zip":"75011","commune":"PARIS 11","libelle":"PARIS","lieudit":""},
{"zip":"75013","commune":"PARIS 13","libelle":"PARIS","lieudit":""},
{"zip":"75019","commune":"PARIS 19","libelle":"PARIS","lieudit":""},
{"zip":"75020","commune":"PARIS 20","libelle":"PARIS","lieudit":""}]
Here is my JS :
$(function(){
$( "#fromzip" ).autocomplete({
source: "/search/autocomplete",
dataType: 'json',
minLength: 3,
});
});
The HTML :
<input
id="fromzip"
name="fromzip"
type="text"
class="form-control"
placeholder="69003"
pattern=".{5}"
title="5 numbers zip"
maxlength="5"
required >
And the PHP (Laravel Input, DB and Response facades) :
public function autocomplete(){
$term = Input::get('term');
$results = array();
$queries = DB::table('zips')
->where('zip', 'LIKE', $term.'%')
->orWhere('libelle', 'LIKE', $term.'%')
->take(30)->get();
foreach ($queries as $query)
{
$results[] = [ 'zip' => $query->zip,
'commune' => $query->commune,
'libelle' => $query->libelle,
'lieudit' => $query->lieudit];
}
return Response::json($results);
}
Have a look at http://api.jqueryui.com/autocomplete/#option-source. It states that the data must be in the format
[ { label: "Choice1", value: "value1" }, ... ]
Your sample data items don't have either of those properties (label or value).
You can modify your server-side script to output the right format, or if you can't/won't do that, you could use the source-as-a-function option in the plugin to write a function that transforms the data.

.ajax and params and how to get them to look like this?

I tried posting a previous question, but i believe it was convoluted.
Basically, i was told "can you make the data come thru like this?" - keep in mind that this data is not derived from a form, but but by data that is driven via a search on the client side.
This is what is suppose to be sent to the server. So if you dumped the error_log, it would look this. This is all dynamic, so the object below will be that format BUT the data will change.
{
"matchedItems" :
[
{ "itemID1" :
{ "Cost" : "12",
"Size" : "small",
"Colors" : [ "blue", "red" ]
}
},
{ "itemdID2" :
{ "Cost" : "33",
"Size" : "large",
"Colors" : [ "yellow" ]
}
}
]
}
so, I run thru the some things on the page and bundle up the data and return data sets, thus the hashes within the array.
BUT for the life of me, I can't get anything to look good in the actual .ajax post. When I console.log the data out, it looks good. Its an array of hashes. etc... looks fine. BUT the following is what is actually sent when I look at the params of the request. So below is what I am actually sending. It did some weird merging and such, it looks like.
{
'matchedItems[0][itemid1][Color]' => 'Blue',
'matchedItems[0][itemid1][Size]' => 'small',
'matchedItems[0][itemid1][Cost]' => '33.90',
'matchedItems[1][itemid2][Color][]' => ['Silver'],
'matchedItems[1][itemid2][Size]' => 'small',
'matchedItems[1][itemid2][Cost]' => '44',
'matchedItems[2][itemid3][Color][]' => ['blue','Red'],
'matchedItems[2][itemid3][Size]' => 'large',
'matchedItems[2][itemid3][Cost]' => '23'
};
I tried to $.params the data, no luck. I tried various data settings in dataType, no luck. I am at a loss on how to format the data I send that mimics what I posted first.
Any ideas?
You should json_encode() your output from PHP
Example:
<?php
$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
echo json_encode($arr);
?>
Output:
{"a":1,"b":2,"c":3,"d":4,"e":5}
You can use jQuery to decode the json you got back from the ajax reply:
var json_reply = jQuery.parseJSON('{"a":1,"b":2,"c":3,"d":4,"e":5}');
alert( json_reply.a ); // alerts "1"

How do I store an array of objects in a cookie with jQuery $.cookie()?

I have a list of javascript objects:
var people = [
{ 'name' : 'Abel', 'age' : 1 },
{ 'name' : 'Bella', 'age' : 2 },
{ 'name' : 'Chad', 'age' : 3 },
]
I tried to store them in a browser cookie with jQuery $.cookie():
$.cookie("people", people);
I then retrieve this cookie and then try to push another object into it:
var people = $.cookie("people");
people.push(
{ 'name' : 'Daniel', 'age' : 4 }
);
However, this does not work; I analyzed this code in Firebug, and Console noted that people was a string ("[object Object],[object Object],[object Object]") and that the push function did not exist.
What is going on? What is the proper way to store and retrieve a list of objects?
Cookies can only store strings. Therefore, you need to convert your array of objects into a JSON string. If you have the JSON library, you can simply use JSON.stringify(people) and store that in the cookie, then use $.parseJSON(people) to un-stringify it.
In the end, your code would look like:
var people = [
{ 'name' : 'Abel', 'age' : 1 },
{ 'name' : 'Bella', 'age' : 2 },
{ 'name' : 'Chad', 'age' : 3 },
];
$.cookie("people", JSON.stringify(people));
// later on...
var people = $.parseJSON($.cookie("people"));
people.push(
{ 'name' : 'Daniel', 'age' : 4 }
);
$.cookie("people", JSON.stringify(people));
I attempted this today and could not get it to work. Later i found out that it was because I had 3 very large objects which I tried to save in a cookie.
The way I worked arround this was by storing the information in the browsers local storage.
example:
localStorage.setItem("test2", JSON.stringify(obj) )
localStorage.getItem("test2")
further info about local storage: cookies vs local storage
4 hours of my time vent to this, dont make the same mistake.

Categories