i need to search by user firstname and lastname where are merge to one. Im working with laravel 5.1 and http://datatables.yajrabox.com/.
Here is me code of backend query:
$orders = Order::select([
'orders.created_at',
'users.firstname AS user_firstname',
'users.lastname AS user_lastname'
])
->join('users', 'users.id', '=', 'orders.user_id')
->where('orders.client_id', \Auth::user()->client_id)
->where('orders.status', 'finished');
And return:
return Datatables::of($orders)
->addColumn('user', function ($user) {
return $user->user_firstname.' '.$user->auser_lastname;
})
->addColumn('action', function ($order) {
return '<div class="btn-group" style="min-width: 76px;">
<i class="fa fa-edit"></i>
<i class="fa fa-times"></i>
</div>';
})
->removeColumn('user_firstname')
->removeColumn('user_lastname')
->make(true);
I merge user column to one with user_firstname and user_lastname.
When im searchng in datatable i need to search by this column - USER. Query to to be like this:
SELECT
`orders`.`created_at`,
`users`.`firstname` AS `agent_firstname`,
`users`.`lastname` AS `agent_lastname`,
FROM
`orders`
INNER JOIN `users` ON `users`.`id` = `orders`.`user_id`
WHERE
`orders`.`client_id` = '3'
AND `orders`.`status` = 'finished'
AND (
LOWER(`orders`.`created_at`) LIKE '%search_word%'
OR LOWER(`users`.`firstname`) LIKE '%search_word%'
OR LOWER(`users`.`lastname`) LIKE '%search_word%'
)
ORDER BY
`orders`.`created_at` DESC
LIMIT 10 OFFSET 0
Here is my datatable JS:
// Data tables
var oTable = $('#orders-data').dataTable({
"processing": true,
"serverSide": true,
"ajax": '/history/orders',
"columns": [
{ data: 'created_at', name: 'orders.created_at' },
{ data: 'user', name: 'user' },
{ data: 'action', name: 'action', orderable: false, searchable: false }
],
});
If I change line { data: 'user', name: 'user' } in JS to { data: 'user', name: 'users.firstaname' } than searching only in users.firstname column, But i need search in users.lastname too.
How to do that?
problem is solved! Here is my code:
$orders = Order::select([
'orders.created_at',
\DB::raw("CONCAT(users.firstname,' ',users.lastname) as user")
])
->join('users', 'users.id', '=', 'orders.user_id')
->where('orders.client_id', \Auth::user()->client_id)
->where('orders.status', 'finished');
function return:
return Datatables::of($orders)
->filterColumn('user', function($query, $keyword) {
$query->whereRaw("CONCAT(users.firstname,' ',users.lastname) like ?", ["%{$keyword}%"]);
})
->addColumn('action', function ($order) {
return '<div class="btn-group" style="min-width: 76px;">
<i class="fa fa-edit"></i>
<i class="fa fa-times"></i>
</div>';
})
->removeColumn('user_firstname')
->removeColumn('user_lastname')
->make(true);
Maybe it helps for others!
Related
I'm creating a list user table on fw laravel by using datatable and axios (not use vuejs), i don't use datatable's pagination but laravel's one because datatables take a lot of time to respond upon retrieving a million records, I can't find a way to use serverside feature cause axios replace ajax feature in severside. The issue began from this:
I'm successful to use laravel's pagination with js but as it comes to 10 or more page, the pagination not update and change the positive upon i click number page, i only can change a page from 1 to 10, here is my pagination code:
display pagination
<div id="pagination">
{!! $axios->links() !!}
</div>
and here is js code
$(document).on('click', '.pagination a',function(e) {
e.preventDefault();
$('li').removeClass('active');
$(this).parent().addClass('active');
let pg = $(this).attr('href')
reloadData(pg)
window.history.pushState("", "",pg)
})
reloadData function:
function reloadData(value){
axios.get(url+'/data'+ value).then(handleResponse)
.catch(function (error) {
console.log(error);
})
function handleResponse(response) {
data = response.data.data;
$('#dataid').DataTable().clear().destroy()
$('#dataid').DataTable({
paging : false,
severSide: true,
processing: true,
deferRender: true,
order: [],
retrieve: true,
pagingType: 'full_numbers',
dom: 'lBfrtip',
columnDefs: [{
"defaultContent": "-",
"targets": "_all"
}],
data: data,
columns: [
{ data: 'name' },
{ data: 'email' },
{ data: 'phone' },
{ data: '' },
{ data: 'created_at' },
{ data: function(data){
return '<td class="pr-0 text-center">'+
'<a id="delete-btn" class="label label-inline label-light-default font-weight-bolder delete-btn" data-id="'+data.id+'" href="javascript:void(0)">Delete'+
'</a>'+ '/'+
'<a id="edit-btn" class="label label-inline label-light-default font-weight-bolder delete-btn" data-id="'+data.id+'" href=" javascript:void(0)">Edit'+
'</a>'+
'</td>'
}}
],
})
}
}
controller :
//display view and pagination
public function index(Request $request)
{
$axios = Apiato::call('User#GetAllUsersAction', [$request]);
$axios->withPath('');
return view('user::Axios.list',compact('axios'));
}
// i retrived the records from this
public function getData(Request $request)
{
//$user = $request->getContent();
//$user = json_decode($user,true);
$axios = Apiato::call('User#GetAllUsersAction', [$request]);
return $axios;
}
i expect something like this upon i click number page : [1],2,3,4,5,...,24,25 --> 1,2,...,[6],7,8,9,...25
I have function delete on my table ( using datatables) this delete is work normally but i want to add some pop up alert like "onclick" on my delete , but its didnt work on my button
public function indexDataTables_pns()
{
$pns = Data_pns::with('users','master_golongan','master_jabatan')->get();
return Datatables::of($pns)->addIndexColumn()
->addColumn('Nama', function ($pns) {
return ''.$pns->users->nama.'';
})
->editColumn('edit', function ($pns) {
return '<i class="glyphicon glyphicon-edit"></i>';
})
->editColumn('hapus', function ($pns) {
$c = csrf_field();
$m = method_field('DELETE');
return "<form action='/delete/$pns->id' method='POST')>
$c
$m
<button style='margin-left:10px; width: 30px;' type='submit'
class='btn btn-xs btn-danger delete' onclick='return
confirm('do you want to delete this data ?')'>
<i class='glyphicon glyphicon-remove-circle'></i>
</button>
</form>";
})
->rawColumns(['Nama' => 'Nama','hapus' => 'hapus','action' => 'action','edit'=>'edit'])
->make(true);
}
its didnt work
i trying adding class
<form action='/delete/$pns->id' method='POST' class='delete-form'>
and add this script
<script>
$('.delete-form').submit(function(event){
if(!confirm('Anda yakin mau menghapus item ini ?')){
event.preventDefault();
}
});
but still didnt work . i put this on under my view .
i try to add onsubmit like this
<form onsubmit='return confirm('Anda yakin mau menghapus item ini ?')'>
still didnt work , iam from this thread this link , but i didnt find the answer ..
look this image
can someone help me ?
UPDATE
i tryng add this form class
return "<form action='/delete/$pns->id' method='POST' class='delete-form')>
this pop up is showing after i click this delete button but this message is null/empty ,
#push('scripts')
<script>
$(function() {
$('#table').DataTable({
processing: true,
serverSide: true,
responsive: true,
ajax: '{!! route('d_pns') !!}',
columns: [
{ data: 'DT_RowIndex', name: 'DT_RowIndex', orderable: false,searchable: false},
{ data: 'Nama', name: 'Nama'},
{ data: 'NIP_lama', name: 'NIP_lama'},
{ data: 'NIP_baru', name: 'NIP_baru'},
{ data: 'TMT_CPNS', name: 'TMT_CPNS'},
{ data: 'TMT_PNS', name: 'TMT_PNS'},
{ data: 'TMT_gol_ruang', name: 'TMT_gol_ruang'},
{ data: 'master_golongan.golongan', name: 'master_golongan.golongan'},
{ data: 'master_jabatan.nama_jabatan', name: 'master_jabatan.nama_jabatan'},
{ data: 'edit', name: 'edit', orderable: false, searchable: false},
{ data: 'hapus', name: 'hapus', orderable: false, searchable: false},
],
});
})
$('.delete-form').submit(function(event){
if(!confirm('Anda yakin mau menghapus item ini ?')){
event.preventDefault();
}
});
</script>
#endpush
why this message on confirm is empty ?
Your 1st attempt issue looks to be escaping the quotes " and '. try putting your message inside double quotes " ". This should resolve your problem
<button style='margin-left:10px; width: 30px;' type='submit'
class='btn btn-xs btn-danger delete' onclick='return
confirm("do you want to delete this data ?")'>
<i class='glyphicon glyphicon-remove-circle'></i>
</button>
SOLVED
Need to add
<script type="text/javascript">
function confirm_delete() {
return confirm('Apakah anda yakin untuk menghapus data ini ? ');
}
</script>
and add onclick return confirm_delete()
I will be dropping this for anyone that need to know how to use onclick from laravel yajra serverside.
$datatable = datatables()->collection($data)
->addColumn('action', function($data){
$button = '
<button type="button" data-security="'.$data->security.'" class="btn btn-warning btn-sm" onclick="OrderTicket(\''.$data->security.'\')">Sell
</button>
<button type="button" data-security="'.$data->security.'" class="btn btn-info btn-sm" onclick="createRequest(\''.$data->security.'\')">Buy
</button>
';
return $button;
})
->rawColumns(['action'])
->addIndexColumn()
->make(true);
return $datatable;
All you have to do is to escape the strings onclick="OrderTicket(\''.$data->security.'\')"
I am working on a page in a Laravel 5.7 application, that has a series of VueJS child components "Prospect" wrapped within a VueJS parent component "Prospects". The child components are table rows that each have a button to delete the row/child. The parent component has a button that deletes multiple child components.
However I am unsure as to how to get the parent component function to call the child component functions to delete the children that have been marked for deletion.
Deleting the child components one at a time from within the child component itself works fine. However I am trying to call the same Child component delete function multiple times from the loop within the parent component function deleteSelectedProspects().
From within deleteSelectedProspects() i need to access the index assigned to the child component, in order to reference the correct row in the $refs array.
How can I access the index of the child component in order to properly reference it in the $refs array inside the selectedBoxes.forEach loop?
Source code for the blade view that contains the Prospects parent component:
#extends('layouts.admin')
#section('content')
<section id="widget-grid">
<div class="row">
<article class="col-xs-12 col-sm-12 col-md-12 col-lg-12 sortable-grid ui-sortable">
<prospects inline-template class="">
<div>
<div class="jarviswidget jarviswidget-sortable" id="wid-id-1" data-widget-editbutton="false" data-widget-deletebutton="false">
<header class="ui-sortable-handle">
<div class="widget-header">
<h2><i class="fa fa-list text-orange"></i> Prospects/Leads List</h2>
</div>
<button class="btn btn-sm btn-primary d-none" #click="markSelectedProspectsContacted" id="btnMarkSelectedProspectsContacted">
<span class="fa fa-check-square-o"></span> Mark Selected as Contacted
</button>
<button class="btn btn-sm btn-danger d-none" #click="deleteSelectedProspects" id="btnDeleteSelectedProspects"><span class="fa fa-trash"></span> Delete Selected</button>
</header>
<!-- widget div-->
<div role="content">
<!-- widget content -->
<div class="widget-body">
<table id="prospectsTable" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>
<label class="vcheck">
<input type="checkbox" id="toggleCheckAllProspects" value="1" /> <span></span>
</label>
</th>
<th>Name</th>
<th>Food Category</th>
<th>Contact</th>
<th>Admin Comments</th>
<th></th>
</tr>
</thead>
<tbody>
<tr is="prospect"
v-for="(prospect, index) in prospects"
:prospect="prospect"
:index="index"
:key="prospect.id"
ref="refIds"
#delete-prospect="removeProspect()"
#update-contacted="updateContacted(index)">
</tr>
</tbody>
</table>
</div>
<!-- end widget content -->
</div>
</div>
<!-- end jarviswidget div -->
</div>
</prospects>
</article>
</div>
</section>
#endsection
#push('js-block')
<script>
$.widget( "ui.tabs", $.ui.tabs, {
_getPanelForTab: function( tab ) {
var id = $( tab ).attr( "aria-controls" );
return $( this._sanitizeSelector( "#" + id ) );
}
});
$(function() {
$('#prospectTabs').tabs({
create: removeLoader($('#prospectTabs'))
});
$('#prospectTabsAdd').click(function() {
$('#add-tab').removeClass('d-none');
});
$('#toggleCheckAllProspects').click(function() {
$('.prospect-check').prop('checked', ($(this).is(':checked') ? true : false));
});
});
</script>
#endpush
Source code for the parent component "prospects":
<script>
export default {
data: function() {
return {
formProspect: {
inputs: {
name: '',
food_cat_id: '',
phone: '',
website: '',
contact_fname: '',
contact_lname: '',
contact_title: '',
address: '',
address2: '',
city: '',
state_id: '',
zip: '',
response_notes: ''
},
headerText: "<i class='fa fa-plus-square-o text-orange'></i> Add Prospect / Lead",
btnText: "<i class='fa fa-plus-square-o'></i> Add Prospect / Lead",
errors: false
},
formSearchProspect: {
inputs: {
keywords: '',
contacted: '',
location: '',
radius: 5
}
},
formProspectMode: 'add',
prospects: []
}
},
computed: {
},
watch: {
formProspectMode: function(newMode) {
switch(newMode) {
case 'add':
this.formProspect.headerText = "<i class='fa fa-plus-square-o text-orange'></i> Add Prospect / Lead";
this.formProspect.btnText = "<i class='fa fa-plus-square-o'></i> Add Prospect / Lead";
this.clearFormProspect();
break;
case 'edit':
this.formProspect.headerText = "<i class='fa fa-edit text-orange'></i> Edit Prospect / Lead";
this.formProspect.btnText = "<i class='fa fa-save'></i> Save Prospect / Lead";
break;
}
}
},
methods: {
fetchProspects() {
var self = this;
$.get('/prospect/fetch', function(r) {
if(r.successMsg) {
self.prospects = r.prospects;
}
})
},
searchProspects() {
var self = this;
var params = {
'keywords' : this.formSearchProspect.inputs.keywords,
'contacted' : this.formSearchProspect.inputs.contacted
};
if(this.formSearchProspect.inputs.location) {
params.location = this.formSearchProspect.inputs.location;
params.radius = this.formSearchProspect.inputs.radius;
}
$.get('/prospect/search', params, function(r) {
if(r.successMsg) {
self.prospects = r.prospects;
}
})
},
addProspect() {
var self = this;
$.ajax({
type: "POST",
dataType: "json",
async: false,
url: "/prospect/add",
data: {
name: this.formProspect.inputs.name,
food_cat_id: this.formProspect.inputs.food_cat_id,
phone: this.formProspect.inputs.phone,
website: this.formProspect.inputs.website,
contact_fname: this.formProspect.inputs.contact_fname,
contact_lname: this.formProspect.inputs.contact_lname,
contact_title: this.formProspect.inputs.contact_title,
address: this.formProspect.inputs.address,
address2: this.formProspect.inputs.address2,
city: this.formProspect.inputs.city,
state_id: this.formProspect.inputs.state_id,
zip: this.formProspect.inputs.zip,
response_notes: this.formProspect.inputs.response_notes
}, success(r) {
if(r.successMsg) {
var newProspect = self.formProspect.inputs;
newProspect.id = r.newId;
newProspect.state = r.state;
newProspect.food_cat = r.food_cat;
console.log(newProspect);
self.prospects.push(Object.assign({}, newProspect));
self.clearFormProspect();
} else if(r.errors) {
self.formProspect.errors = r.errors;
}
}
});
},
saveProspect() {
var self = this;
$.post('/prospect/edit', {
id: this.formProspect.inputs.id,
name: this.formProspect.inputs.name,
food_cat_id: this.formProspect.inputs.food_cat_id,
phone: this.formProspect.inputs.phone,
website: this.formProspect.inputs.website,
contact_fname: this.formProspect.inputs.contact_fname,
contact_lname: this.formProspect.inputs.contact_lname,
contact_title: this.formProspect.inputs.contact_title,
address: this.formProspect.inputs.address,
address2: this.formProspect.inputs.address2,
city: this.formProspect.inputs.city,
state_id: this.formProspect.inputs.state_id,
zip: this.formProspect.inputs.zip,
response_notes: this.formProspect.inputs.response_notes
}, function(r) {
if(r.successMsg) {
var savedProspect = self.prospects.filter(prospect => prospect.id == self.formProspect.inputs.id)[0];
savedProspect = Object.assign({}, self.formProspect.inputs);
self.formProspectMode = "add";
} else if(r.errors) {
self.formProspect.errors = r.errors;
}
});
},
removeProspect(index) {
this.prospects.splice(index, 1);
},
clearFormProspect() {
this.formProspect.inputs = {};
this.formProspect.errors = false;
},
deleteSelectedProspects() {
var self = this;
var selectedBoxes = self.prospects.filter(prospect => prospect.selected);
$.SmartMessageBox({
title: "<i class='fa fa-trash text-orange-dark'></i> Delete (" + selectedBoxes.length + ") Selected Prospects",
content: "Are you sure you want to delete the selected leads?",
buttons: "[No][Yes]"
}, function(e) {
if("Yes" == e) {
selectedBoxes.forEach(function(p) {
var lostChild = self.prospects.filter(prospect => prospect.id == p.id);
// HOW CAN I ACCESS THE INDEX OF THE LOST CHILD TO REFERENCE IT IN THE $refs ARRAY BELOW
// HOW CAN I ACCESS THE INDEX OF THE LOST CHILD TO REFERENCE IT IN THE $refs ARRAY BELOW
//self.$refs.refIds[lostChildIndex].deleteProspect();
});
}
});
},
markSelectedProspectsContacted() {
var self = this;
var selectedBoxes = self.prospects.filter(prospect => prospect.selected);
$.SmartMessageBox({
title: "<i class='fa fa-trash text-orange-dark'></i> Mark (" + selectedBoxes.length + ") Selected Prospects as Contacted",
content: "Are you sure you want to mark the selected leads as contacted?",
buttons: "[No][Yes]"
}, function(e) {
if("Yes" == e) {
selectedBoxes.forEach(function(p) {
/*
mark contacted
*/
});
}
});
},
updateRadiusSearchDiv() {
if($('#searchLocation').val()) {
$('#radiusSearchDiv').removeClass('d-none');
} else {
$('#radiusSearchDiv').addClass('d-none');
}
}
},
mounted() {
this.fetchProspects();
setTimeout(function() {
$('#prospectsTable').DataTable({
"columnDefs": [
{ "orderable": false, "targets": [0,4,5] }
],
"language": {
"search": "Filter Results:"
},
"dom": "ftilp"
});
$('#prospectsTable > thead > tr th:first-child').removeClass('sorting_asc');
}, 500);
$('#btnDeleteSelectedProspects, #btnMarkSelectedProspectsContacted').removeClass('d-none');
}
}
</script>
Source code for the child component "prospect":
<template>
<transition name="fade">
<tr v-if="show">
<td class="text-center align-middle">
<label class="vcheck">
<input type="checkbox" class="prospect-check" value="1" v-model="prospect.selected" /> <span></span>
</label>
</td>
<td>
<div>{{ prospect.name }}</div>
<div v-show="prospect.contacted" class="label label-success"><span class="fa fa-check-square-o"></span> Contacted!</div>
</td>
<td>{{ prospect.food_cat.title }}</td>
<td>{{ prospect.contact_fname }}<span v-if="prospect.contact_lname"> {{ prospect.contact_lname }}</span><span v-if="prospect.contact_title">, {{ prospect.contact_title }}</span></td>
<td>{{ prospect.response_notes }}</td>
<td class="text-right align-middle">
<button class="btn btn-primary" #click="updateContacted" v-show="!prospect.contacted"><span class="fa fa-check-square-o"></span> Mark As Contacted</button>
<button class="btn btn-primary" #click="editProspect"><span class="fa fa-edit"></span> Edit Lead</button>
<button class="btn btn-danger" #click="removeProspect"><span class="fa fa-trash"></span> Delete Lead</button>
</td>
</tr>
</transition>
</template>
<script>
export default {
props: ['prospect', 'index'],
data: function() {
return {
prospectData: this.prospect,
show: true,
prospectIndex: this.index
}
},
methods: {
editProspect() {
this.$parent.formProspect.inputs = this.prospectData;
this.$parent.formProspectMode = "edit";
$('#prospectTabs').tabs('option', 'active', 1);
$('#add-tab').removeClass('d-none');
window.scrollTo({ top: 0, behavior: 'smooth' });
},
updateContacted() {
var self = this;
$.SmartMessageBox({
title: "<i class='fa fa-trash text-orange-dark'></i> Mark as Contacted?",
buttons: "[No][Yes]"
}, function(e) {
if("Yes" == e) {
$.post('/prospect/updateContacted/' + self.prospectData.id, function(r) {
if(r.successMsg) {
self.$emit('update-contacted');
}
});
}
});
},
removeProspect() {
var self = this;
$.SmartMessageBox({
title: "<i class='fa fa-trash text-orange-dark'></i> Delete Prospect/Lead",
content: "Are you sure you want to delete this prospect/lead?",
buttons: "[No][Yes]"
}, function(e) {
if("Yes" == e) {
self.deleteProspect();
}
});
},
deleteProspect() {
var self = this;
$.post('/prospect/delete/' + self.prospectData.id, function(r) {
if(r.successMsg) {
self.show = false;
self.$emit('delete-prospect');
}
});
}
},
mounted() {
}
}
</script>
Your code is a little bit confused so this is just an idea that should work well, though. You should not touch refs, you just need to change the data model. Remove from the data movel and components will remove themselves.
In the parent component add a method called, say, checkProspect like
data: {
...
checkedProspects: []
},
methods: {
checkProspect(prospectId){
checkedProspects.push(prospectId);
},
deleteCheckedProspects(){
// Remove from the model by checkedProspects ids
}
}
Then add the handler:
<tr is="prospect"
v-for="(prospect, index) in prospects"
:prospect="prospect"
:index="index"
:key="prospect.id"
ref="refIds"
#checkProspect="checkProspect"
#delete-prospect="removeProspect()"
#update-contacted="updateContacted(index)">
In the child component, when you click to check it, emit the event:
this.$emit('checkProspect', this.id);
I'm trying to create project like Trello. I do not know how to do it properly.
I created function init in AngularJS Controller where i put http requests:
$scope.loadLists();
$scope.loadsCards();
Scripts:
$scope.loadLists = function () {
return ApiService.staff.list()
.then(function (resp) {
for (var i = 0; i < resp.length; i++) {
$scope.lists[i] = resp[i];
}
})
}
$scope.loadsCards = function () {
return ApiService.staff.cards()
.then(function (resp) {
for (var i = 0; i < resp.length; i++) {
$scope.cards = resp;
}
console.log($scope.cards)
})
}
I'm downloading tasks to $scope.cards
In console.log() we can see:
Array [ Object, Object, Object, Object, Object, Object, Object, Object ]
where the object consists of
var CardSchema = new Schema({
name: { type: String, maxlength: 20, required: true },
list: { type: Schema.Types.ObjectId, ref: 'List' },
updated: { type: Date, default: Date.now },
created: { type: Date, default: Date.now },
active: Boolean
});
And now I do not know what to do so that the cards are displayed only those in the given column that are assigned to the list. I mean : task.list == list._id
for the moment I did it
<div ng-repeat="list in lists track by $index">
<div style="float: left; margin-left: 5px;">
<div id="tasks">
<h3>{{list.name}}</h3>{{$index}}
<ul>
<li ng-repeat="task in cards">
<div ng-hide="task.list == list._id">
{{task.name}}
</div>
<i ng-click="removeTask(task)" class="fa fa-trash-o"></i></li>
</ul>
<form ng-submit="addTask(list._id, $index, newTask)">
<input type="text" ng-model="newTask" placeholder="add a new task" required />
</form>
</div>
</div>
</div>
But it does not work and so it probably can not be if I want to still create a database for the card field
Position (Later to enable drag & dropping)
Can anyone tell me how to properly display cards in lists?
EDIT;;;
thank you very much for the help.
Can you explain more to me because I still have a problem with the cards
I did directiv in angularJS:
App.directive('myList', function() {
return {
restrict: 'E',
replace: true,
template: '<div style="float: left; margin-left: 5px;"><div id="tasks">{{list.name}}<br>{{card.name}}</div></div>'
};
});
App.directive('myCard', function() {
return {
restrict: 'E',
replace: true,
template: '<div style="float: left; margin-left: 5px;"><div id="tasks">{{card.name}}</div></div>'
};
});
and in index.ejs
<my-list ng-repeat="list in lists" list-data="list"></my-list>
<my-card ng-repeat="card in listData.cards" card-data="card"></my-card>
I also did AJAX inquiry after all cards :
https://gist.github.com/anonymous/ed17c3fd675ea4361cb8fbd78e94cb37
name: its name card
list: its _id list
In $scope.cards I stores AJAX inquiry after all cards,
Its my card model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CardSchema = new Schema({
name: { type: String, maxlength: 20, required: true },
// description: { type: String, maxlength: 300 },
list: { type: Schema.Types.ObjectId, ref: 'List' },
updated: { type: Date, default: Date.now },
created: { type: Date, default: Date.now },
active: Boolean
});
module.exports = mongoose.model('Card', CardSchema);
And I have no idea how this loop looks, would you help me somehow?
It's not that easy to solve with two ng-repeat's. You may want to create your list and card directives because eventually they will be complex views:
<my-list ng-repeat="list in lists" list-data="list"></my-list>
And in my-list directive, you can create a loop to to render cards:
<my-card ng-repeat="card in listData.cards" card-data="card"></my-card>
I am learning Meteor JS and followed a tutorial to build a menu builder shopping list. I am trying to add some features to it. I added one feature successfully, but now I am trying to create an organization feature where users can join an organization and see all shopping lists related to that organization. The first step is to allow for adding an organization by users.
The form appears, and I was able to insert in to the database from the console, but when I use autoform the objects are not being inserted into the database.
I recently upgraded from Meteor 1.3 to 1.4. I don't believe that is an issue since all of the other forms on the app are inserting properly still.
I have a feeling it has something to do with subscribe/publish, but I am not sure what I am doing wrong.
HTML- neworganization.html
<template name='NewOrganization'>
<div class='new-organization-container'>
<i class='fa fa-close'></i>
{{#autoForm collection='Organizations' id='insertOrganizationForm' type='insert'}}
<div class='form-group'>
{{> afQuickField name='organization'}}
</div>
<div class='form-group'>
{{> afQuickField name='members'}}
</div>
<button type="submit" class="btn btn-primary">Add</button>
{{/autoForm}}
</div>
</template>
organizations.html
<template name='Organizations'>
<h3>Your Organizations</h3>
{{#if $.Session.get 'newOrganization'}}
{{> NewOrganization }}
{{else}}
<button class='btn btn-organization btn-primary'>Add an Organization</button>
<button class='btn btn-join'>Join an Organization</button>
<button class='btn btn-deny'>Leave an Organization</button>
{{/if}}
<section class='organization-list'>
{{#if Template.subscriptionsReady}}
{{#each organizationList}}
{{> OrganizationItem}}
{{/each}}
{{else}}
<p>Loading...</p>
{{/if}}
JS- organizations.js
Template.Organizations.onCreated(function() {
this.autorun(() => {
this.subscribe('organizations');
});
});
Template.Organizations.helpers({
organizations() {
return Organizations.find({});
}
});
Template.Organizations.events({
'click .btn-organization': () => {
Session.set('newOrganization', true);
}
});
Template.NewOrganization.helpers({
organizationList: () => {
var organizationItems = Organizations.find({});
return organizationItems;
}
});
newOrganization.js
if (Meteor.isClient) {
Meteor.subscribe('organizations');
}
Template.NewOrganization.events ({
'click .fa-close': function () {
Session.set('newOrganization', false);
}
});
collections/organizations.js
import SimpleSchema from 'simpl-schema';
SimpleSchema.extendOptions(['autoform']);
Organizations = new Mongo.Collection('organizations');
Organizations.allow({
insert: function(userId){
return !!userId;
},
update: function(userId, doc){
return !!userId;
}
});
OrganizationSchema = new SimpleSchema ({
organization: {
label: "Organization Name",
type: String
},
id: {
label: "ID",
type: String,
autoform: {
type: "hidden"
}
},
members: {
type: Array
},
"members.$": Object,
"members.$.name": String,
"members.$.role": String,
inOrganization: {
type: Boolean,
defaultValue: true,
autoform: {
type: 'hidden'
}
},
createdAt: {
type: Date,
label: "CreatedAt",
autoform: {
type: "hidden"
},
autoValue: function() {
return new Date();
}
}
});
Meteor.methods({
deleteOrganizations: function(id) {
Organizations.remove(id);
}
});
Organizations.attachSchema(OrganizationSchema);
The problem is in the way the Schema was designed. I had inserted an id into the schema. My reasoning was that I wanted to have a way to add and remove members from an organization. What I did not take into account was that Mongo autogenerates an id for database object and by designing my schema in this way, I was creating a conflict. I removed the id from my schema and removed the problem.
Here is the new collections/organizations.js file:
import SimpleSchema from 'simpl-schema';
SimpleSchema.extendOptions(['autoform']);
Organizations = new Mongo.Collection('organizations');
Organizations.allow({
insert: function(userId){
return !!userId;
},
update: function(userId, doc){
return !!userId;
}
});
OrganizationSchema = new SimpleSchema ({
organization: {
label: "Organization Name",
type: String
},
members: {
type: Array
},
"members.$": Object,
"members.$.name": String,
"members.$.role": String,
inOrganization: {
type: Boolean,
defaultValue: true,
autoform: {
type: 'hidden'
}
},
createdAt: {
type: Date,
label: "CreatedAt",
autoform: {
type: "hidden"
},
autoValue: function() {
return new Date();
}
}
});
Meteor.methods({
deleteOrganizations: function(id) {
Organizations.remove(id);
}
});
SimpleSchema.debug = true;
Organizations.attachSchema(OrganizationSchema);