Laravel 4 AngularJS remove record from database - php

I've been working on a small app that uses Laravel 4 as the backend with AngularJS as a starting point (mainly to learn angularjs).
The idea is that I can add bookmarks via a form and have these show up in a searchable table. I've got it working where I can post to the database and save the records. The following does that job perfectly for my needs.
$scope.addLink = function () {
var link = {
title: $scope.newTitle,
address: $scope.newAddress,
type: $scope.newType
};
$scope.links.push(link);
$http.post('bookmarks', link);
};
However, I can't work out how to delete a row. Well, I can remove it in the table but not from the database using routes. I have got a ng-click function that removes the row from the table using splice but don't know how to send the details to the Laravel route to remove from the database. So far I have this:
$scope.remove = function ( idx ) {
var link = $scope.links[idx];
$scope.links.splice(idx, 1);
$http.delete('removemark/{link.id}');
};
Clearly the $http.delete is not set up correctly but not sure how to do it.
I have the route as this:
Route::delete('removemark /{id}', function($id)
{
Bookmark::destroy($id);
});
But this isn't working. Hopefully some one can point me in the next direction.

you need to build the url string yourself.
$scope.remove = function ( idx ) {
var link = $scope.links[idx];
$http.delete('removemark/' + link.id).success(function(response){
/* should validate response and then remove from array */
$scope.links.splice(idx, 1);
}).error(function(err){
/* do something with errors */
});
};
I would suggest you leave the item in the array until you have confirmed delete from server response and then remove it from array.
Use your browser console network tab to inspect requests. You likely would see a 404 status with what you had and would give you clues where things weren't quite right

Related

DataTables 1.10: Using saveState to remember filtering and order but need to update address URL to have shareable link for others

I use saveState: true to keep the conditions for my DataTables when ordering columns or filtering results with a phrase. When I refresh the page, conditions remain thanks to the local storage.
This works great within the same browser, but imagine a quite common case when after you apply both ordering and filtering to your table, you would like to share this state with your friend by simply copying and pasting a long URL with query string so that when he / she opens it, the table looks exactly the same.
There was a plugin that used to do this but it's not maintained and after giving it a try, it does not work with 1.10 at all.
I wonder if it's possible to solve this by using just some native code and maybe replaceState to simply update URL when applicable?
This is my JS.
$(function () {
let table = $('.table').DataTable({
processing: true,
serverSide: true,
stateSave: true,
stateSaveCallback: function (settings, data) {
// save state
},
stateLoadCallback: function (settings) {
// read state and change url?
},
ajax: '{{ route('admin.api.dt.customer.index') }}',
columnDefs: [{
orderable: false,
targets: 2
}],
pageLength: {{ \App\Repositories\Sync\CustomerRepository::PER_PAGE_DATA_TABLES }},
});
});
Based on this code the obvious issue is that the ajax URL is my hardcoded Laravel route. Simply passing query string does not work.
My Laravel route is simply: http://iosportal.local/admin/api/customer and it returns JSON shaped to suit DataTables.
Can somebody give my a hint how to approach this?
I found storing the current state as base64 was easy and portable. You'll need to create some sort of UI for retrieving the state which could be anything, but at it's most primitive you can have a button:
<a id="get-state">Get State</a>
And do something like this:
$('#get-state').on('click', function() {
var saved = btoa(JSON.stringify(table.state()));
alert('state=' + saved);
})
Now append that as a query parameter to get your shareable url:
https://example.com?state=eyJzZWFyY2giOnsic2VhcmNoIjoibWVvdyIsInNtYXJ0Ijp0cnVlLCJyZWdleCI6ZmFsc2UsImNhc2VJbnNlbnNpdGl2ZSI6dHJ1ZX19
To restore the state have something like this in your datatable options:
// use stateLoadParams() instead of stateLoadCallback() since the former
// is designed for exactly what you want — manipulating the loaded state
"stateLoadParams": function (settings, data) {
// check the current url to see if we've got a state to restore
var url = new URL(window.location.href);
var state = url.searchParams.get("state");
if (state) {
// if so, try to base64 decode it and parse into object from a json
try {
state = JSON.parse(atob(state));
// now iterate over the object properties and assign any that
// exist to the current loaded state (skipping "time")
for (var k in state) {
if (state.hasOwnProperty(k) && k != 'time') {
data[k] = state[k];
}
}
} catch (e) {
console.error(e);
}
}
}
Note I'm skipping the "time" attribute here since it may invalidate your state expiry.
#billynoah's stateLoadParams utilization should work for most of the scenarios, however stateLoadParams is being fired only when there is already some saved state in local storage - so when you are accessing given URL for the first time it will not work.
Much cleaner way how to achieve sharing through URL is to edit stateSaveCallback and stateLoadCallback so they will not use local storage at all and will use url parameters instead.
This is all you need to add into respective datatable config. It also updates URL without need of reload on every state change (or state save to be more precise) and it works for multiple tables as well. The only requirement is that every table element has to have its own specific ID.
stateSaveCallback: function (settings, data) {
//encode current state to base64
const state = btoa(JSON.stringify(data));
//get query part of the url
let searchParams = new URLSearchParams(window.location.search);
//add encoded state into query part
searchParams.set($(this).attr('id') + '_state', state);
//form url with new query parameter
const newRelativePathQuery = window.location.pathname + '?' + searchParams.toString() + window.location.hash;
//push new url into history object, this will change the current url without need of reload
history.pushState(null, '', newRelativePathQuery);
},
stateLoadCallback: function (settings) {
const url = new URL(window.location.href);
let state = url.searchParams.get($(this).attr('id') + '_state');
//check the current url to see if we've got a state to restore
if (!state) {
return null;
}
//if we got the state, decode it and add current timestamp
state = JSON.parse(atob(state));
state['time'] = Date.now();
return state;
}

Send multiple AJAX data to PHP and update Mysql database

i am tying to build an application where user can reorder items (and save the order to database). The items user is reordering are navigation links, which are generated dynamically on the page from php loop:
$nav_links.='<li class="collection-item ui-state-default item" data-ord="'.$navorder.'" data-url="'.$pageurlname.'"><a>' .$pagename. '</a></li>';}
$navorder is order of the page in the navigation
$pageurlname is string which is used to call the page dynamically (index.php?page=$pageurlname) and is unique key in the table.
I am using jqueryUi sortable funcion to make the process drag & drop, it is working fine and each time i reorder the links, the new order is updated to "data-ord".. the sript:
$('#sortable').sortable({
stop: function(event, ui){
$(".sortable li").each(function(i, el){
$(el).attr('data-ord',$(el).index()+1);
});
}
});
Now to the problem, which is my ajax script:
$(document).on('click','.saveorder',function(){
var neworder = $('.collection-item').attr('data-ord');
var pgurl = $('.collection-item').attr('data-url');
$.ajax({
type:'POST',
dataType:'text',
url:'/rs/pages/nav_order.php',
data: { neworder:neworder, pgurl:pgurl },
success: function(data) {console.log(data); $('#response').html(data);},
error: function(data) {console.log('Error!', data); }
});
});
I am new to ajax, so it is mostly build on scripts i found in other quiestions here. (I was able to succesfully implement cript link this to my other functions) however it is not working in this case. The problem seems to be that i am trying to post multiple data for multiple rows (At this time i have 4 links i am trying to reorder, but the link count can be more or less). When i tried to get values of variables "neworder" and "pgurl" (using alert), it always show only the values for the first item.
I have tried lot of solutions found in similar quiestion but none of them worked, simply because user were posting form data and then serialized it, which is not my case because i am not sending data from the form.
Lastly here is the nav_order.php (i guess it is wrong here too, probably need to add foreach but at first i need to have the ajax working correctly):
<?php
include "/rs/include/db.php";
$neworder = $_POST['neworder'];
$pgurl = $_POST['pgurl'];
$query = mysqli_query($Connection, "UPDATE horus_pages SET nav_order='$neworder' WHERE url_name='$pgurl'") or die (mysqli_error($Connection));
echo 'Reordered';
?>
Also when i check the console, there is no data.
So please can you tell me how to correct the ajax script to send the data for each object and then handle it correctly in the php script? Hope i described my problem clearly. Thank you for any help.
Put data-id="your_database_id" in your links html. Selecting them in your database with href, will be slow and bug things if there are multiple records with the same href.
You have save button which sends the order and href of the first link it finds? And what happens when multiple items change their order? If you have many links, you will be throwing hundreds of mysql updates for each save?
You should be better off sending json to your php. Something like that:
[{id:123, order: 332}, {id:124, order:334}, ... ]
dataType:'text' becomes dataType:'json'
If you don't care about scalability, then this will work on the backend.
$data = file_get_contents("php://input");
$links = json_decode($data, true);
foreach($links as $link) {
$order = intval($link['order']);
$id = intval($link['id'])
// UPDATE table SET `order` = '$order' WHERE id = '$id'
}
Btw. Your php code allows SQL injection. Thats bad
Perhaps you can make the order 'float' and make an algorithm which finds empty spot. This will allow you to reduce these 100's of SQL requests to 1.

load more content from an array using codeigniter

I am using CodeIgniter. In my controller I am decoding a JSON response and simply displaying the values upon loading a view. I am simply displaying all my content from a JSON array (no database used). It is completely an array from which i am rendering the data.I want to autoload the content whilst scrolling.
Example:
$resultjson = $this->curl->simple_get("http://www.test.com/api/records.php?ak=XXXXXXXX&ts=XXXXXXXX&sig=XXXXXXXX&postano=XXXXXX&count=100");
How can I fetch 10 records when autoloaded? Just like the http://pinterest.com/ mechanism. How can I achieve this?
Are there any plugins? Does CodeIgniter already have a solution for it such that I can use classes or libraries?
You can use the jQuery scroll event, scrollTop() and the $.ajax();
Basicly catch the scroll event, see if $(window).scrollTop() is higher than <div id="auto_load"></div> (through .offset()) and run ajax once if that's the case.
div#auto_load would be places bellow loaded content, and will "jump" down once content is added.
Example:
var ajax_once = false;
$(window).bind('scroll', function() {
if (ajax_once)
return;
if ($(this).scrollTop() >= $('div#auto_load').offset().top) {
ajax_once = true;
$.ajax({
/* Url, dataType json etc. */
}).done(function(data) {
/* use the data */
ajax_once = false;
});
}
});
Codeigniter is a php framework which means server side therefore no client side logic built in.
You can use a jQuery plugin for that called infinite scroll. Here is the link to it: http://www.infinite-scroll.com/

connect AngularJS to mysql using my PHP service?

I am using AngularJS 1.0, PHP, and mysql with localhost on my Mac.
I have a very simple mysql database: "cats". It has one table called "kittens". The table has two columns, "id" and "name". There are three kittens in the database with names Larry, Curly, and Moe.
Now, I have some simple PHP code which opens the dbase, gets the three records, and returns them in JSON like this:
[{"id":"1","name":"Larry"},{"id":"2","name":"Curly"},{"id":"3","name":"Moe"}]
I used the latest angular-seed and set up a project in Eclipse. In app.js I wrote this:
'use strict';
angular.module('Cats', ['ngResource','Cats.filters', 'Cats.services', 'Cats.directives'])
I put my PHP code in the services folder and named it "index.php". If I navigate to that services/index.php in my browser using localhost on the Mac, I get back the JSON above. So far everything is cool.
Now - ALL I WANT TO DO (!famous last words ;) is connect to the PHP service I have and display the contents of that Cats table on my main index page using my AngularJS project. Plain old text, no tables, just bind to the available resource and display it.
I have tried all manner of demos online (many are out of date). Can anyone show me one simple, current way to do this? For the life of me I have all kinds of AngularJS demos working but none of them does this simple task in a way I can understand.
Thank you in advance.
This should also work. It's significantly fewer lines of code, but note that any error handling has been removed:
function FetchCtrl($scope, $resource) {
var services = $resource('../services/index.php');
$scope.data = services.query();
}
FetchCtrl.$inject = ['$scope', '$resource'];
Normally I would have used the built in .get() method on the $resouce but your response is in the form of an Array, which .query() supports by default.
You can find the documentation on $resource here
OK. Solved it. First, copied and added a controller I found in one of the examples:
function FetchCtrl($scope, $http, $templateCache) {
$scope.method = 'GET';
$scope.url='../services/index.php';
$scope.fetch = function() {
$scope.code = null;
$scope.response = null;
$http({method: $scope.method, url: $scope.url, cache: $templateCache}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
}).
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
$scope.updateModel = function(method, url) {
$scope.method = method;
$scope.url = url;
};
}
Then, I added a route controller to my module:
var module = angular.module('Cats', ['ngResource','Cats.filters', 'Cats.services', 'Cats.directives'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/main', {templateUrl: 'partials/partial1.html', controller: MyCtrl1});
Finally, on that partial1.htm page, I added this:
<div ng-init="fetch()">
{{data}}
</div>
Now when I go to that page in the browser, I can see the entire database dumped out in JSON. Ahhhh. Clearly there are many more sophisticated things to try, etc etc but I needed this simple result so I could be certain that I did in fact have a model arriving when summoned. Angular dies silently in many cases, so a visible result was quite helpful.
One gotcha: be careful that the php file is executable by more than yourself as user. I don't know the name of the user that AngularJS implements but I had to chmod 644 index.php so the app could use it.
I hope that helps someone.

Ajax results back to mysql

I am trying to send the results of the current drag drop state back to mysql using ajax/php.
The console .log works fine..
With some help the drag and drop jquery feature is all working perfectly however sadly jquery/ajax is really not in my bag of tricks ..
http://jsfiddle.net/ambiguous/FMKmj/ (Credit mu)
Tearing my hair out , any ideas ?
If you just want to submit the groups hash, do it like:
$('#submit').click(function() {
var groups = { };
$('.sort').each(function() {
var a = [ ];
$(this).find('li').each(function() {
a.push(this.id);
});
groups[this.id] = a;
});
console.log(groups);
$.ajax({
url: "yourscript.php",
data: groups,
success: function(){
alert('sent!');
}
});
});
Step 1: Catch the event
Notice that in the JQuery UI doc for sortable there is an event tab: here.
So you have to bind an event to an Ajax call inside the event handling function called when a block is dropped in a new box.
Step 2: The Ajax call
It means you have to write your Ajax call: see here.
Typically, you will do a post request since moving a block from a place to another place will change something on the server side.
What do you send to the server ?
Basically you want to send to the server which block has moved where. But it is up to you, you can send whatever you want, it depends on you server side application.
Step 3: The server side
The server based on this information can execute MySQL requests.

Categories