Laravel with angularJS load template after $http call - php

I am using Laravel with AngularJs trying to fetch data using $http method of angularJS
I got data successfully but the problem is that I want to redirect to another page to show the result how can I achieve this using AngularJs?
Here is my jobs.js controller
app.controller('JobsController', function($scope, homepagesearchService) {
$scope.opts = [];
$scope.city = ["All", "Dubai", "Abu Dhabi", "sharjah", "ras al khaimah", "ajman", "umm al quwain", "fujairah", "Al Ain"];
for (var i = 0; i <= 30; i++) {
$scope.opts.push(i);
}
$scope.homepageSearch = function(search) {
homepagesearchService.getData(search).then(function(data) {
$scope.result = data;
console.log(data);
});
}
});
A service to get data from database
angular.module('jobs').factory('homepagesearchService', function($http){
return {
getData: function(search){
if(angular.isUndefined(search.keyword)){
search.keyword = 'search-job';
}
return $http({
method : 'POST',
url : '/search/'+angular.lowercase(search.keyword).replace(/[^a-zA-Z0-9_]/g,'-')+'-'+'jobs',
data : search, //forms user object
headers : {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(function(result){
return result.data;
});
}
}
});
JobsController from where I got the data
<?php
/*
*Developer: Kritika Shrivastava
*Jobs Controller to Fetch All Jobs
*
*/
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use App\Jobs;
class JobsController extends Controller
{
/**
* Show the application welcome.
*
* #return \Illuminate\Http\Response
*/
public function welcome(){
return view('welcome');
}
/*
*
*Ajax Call to search Home Page
*
*/
public function homepageSearch(){
$_POST = json_decode(file_get_contents('php://input'), true);
$jobs = Jobs::latest('created_at')->search()->get();
echo $jobs;
}
}
This is my search form
#extends('layouts.app')
#section('content')
<div ng-app="jobs">
<div class="m-banner-1" ng-controller="JobsController">
<div class="main ui container m-banner-1-cover" >
<form ng-submit="homepageSearch(search)">
<div class="ui grid">
<div class="sixteen wide mobile five wide tablet five wide computer column auto-k">
<p style="color:#ffffff;font-size:20px;">Enter Keywords</p>
<div class="ui fluid icon input">
<input type="text" placeholder="Search a very wide input..." ng-model="search.keyword">
</div>
</div>
<div class="sixteen wide mobile five wide tablet five wide computer column ui fluid">
<p style="color:#ffffff;font-size:20px;">Location</p>
<select class="ui fluid normal dropdown"
ng-options="cit for cit in city" ng-model="search.city">
</select>
</div>
<div class="sixteen wide mobile five wide tablet five wide computer column">
<p style="color:#ffffff;font-size:20px;">Experience</p>
<select class="ui fluid normal dropdown" ng-model="search.experience"
ng-options="opt as opt for opt in opts">
<option value="">Years</option>
</select>
</div>
<div class="sixteen wide column align center">
<button class="ui massive button orange-btn wide-bt">Find Jobs</button>
</div>
</div><!--ui grid-->
</form>
</div><!--ui container-->
</div><!--m-banner-1-->
</div>
<br>
<br>
#endsection
I want when user clicks search button it should redirect to another page and display data got from Ajax call.
Also please suggest is this the correct way of achieving this using AngularJS.
I am new to AngularJs and Laravel.

There are multiple ways to achieve this.
1. Load data in a service. After get data from http
$scope.homepageSearch = function(search) {
homepagesearchService.getData(search).then(function(data) {
$scope.result = data;
DataService.set(data);
// and move to another page using $state.go('whatever page you want')
console.log(data);
});
}
//in that page load data from service
var data = DataService.get()// and here you can use that data
//in service
//make a var holdingdata; like
set(data){
holdingdata = data;
}
get(){
return holdingdata;
}
you can use localStorage after http success save data in local storage, and move to another page and get data from localStorage
you can also use $state service of angular like
$state.go('toState', { 'data':httpData});
and from that page get data from param using $stateParam service of anguar.
***From my point of view method 1 and 3 is good. you can use any of them.

I consider another page means ANOTHER VIEW OF ANGULAR APP:
app.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/router-url', {
controller: 'AnotherController',
templateUrl: 'Partials/ViewStart.html'
})
$scope.homepageSearch = function(search) {
homepagesearchService.getData(search).then(function(data) {
$scope.result = data;
console.log(data);
$location.path('/router-url/');
});
}

Related

How to delete data from DB using React, and hitting a rest API that i created using php and mysql?

The api works fine because I already tested it in postman, and I've managed to create the front end and show all the data stored in my api, now I want to press a button and delete the particular item I want.
When I press the delete button, an alert pops up with the id of the current item, so I know passing the id isn't an issue. The problem is when I use the fetch function.
Here's the delete function from my api:
public function delete(){
//crear query
$query = 'DELETE FROM ' . $this->table . ' WHERE ID = :ID';
//prepare statement
$stmt = $this->conn->prepare($query);
//clean data
$this->ID = htmlspecialchars(strip_tags($this->ID));
//bind data
$stmt->bindParam(':ID', $this->ID);
//execute query
if($stmt->execute()){
return true;
}
//print error if something goes wrong %s es un placeholder
printf("Error: %s. \n", $stmt->error);
return false;
}
Here's the react code (check the function handleBorrar):
import React from 'react';
class Pelicula extends React.Component{
constructor(props){
super(props);
this.state={
loading:true,
pelicula:null,
};
}
async handleBorrar(id) {
alert(`hello, ${id}`);
const responseDel = await fetch(`http://localhost/APIpeliculas/api/pelicula/read.php/${id}`, {
method: "DELETE",
});
return responseDel.json();
}
async componentDidMount(){
const url = "http://localhost/APIpeliculas/api/pelicula/read.php";
const response = await fetch(url);
const result = await response.json();
this.setState({pelicula:result.data, loading: false});
document.body.style.backgroundColor = "burlywood";
}
render(){
if (this.state.loading){
return <div> loading... </div>
}
if(!this.state.pelicula){
return <div> Sin peliculas... </div>
}
return(
<div className="container">
<div className="row">
{
this.state.pelicula.map((peli, index)=>{
return(
<div key = {index} className="col-sm-12 col-md-6 col-lg-4 mt-3 d-flex justify-content-center col-style">
<div className="card card-style">
<div className="card-body">
<h5 className="card-title">{peli.Nombre}</h5>
<h6 className="card-subtitle mb-2 text-muted">{peli.Categoria}</h6>
<p className="card-title"> {peli.Director} </p>
<button type="button" className="btn btn-labeled btn-danger" onClick={() => this.handleBorrar(peli.ID)}> Borrar </button>
<button type="button" className="btn btn-labeled btn-warning"> Editar </button>
</div>
</div>
</div>
)
})
}
</div>
</div>
)
}
}
export default Pelicula;
I got some ideas for the fetch DELETE method by reading another questions from here, but I'm not sure how it will work. What is the json that will return? Also, will react render everything again and call the api to update everything or will I have to reload the page to see the results?
Also, I'm not sure if I'm using the right url, since when I made the api and tested it in postman, to delete and item I have to use the url: http://localhost/APIpeliculas/api/pelicula/delete.php and then pass the ID on the body as a JSON object. So I'm not sure how will it work, since the route for my api won't take a delete.php/ID route.
If you're using a RESTful API, there's no mandatory response when you delete a resource successfully. You can return status 204 when the resource is deleted and some of the 400 statuses when something goes bad. See this question for suggestions. You don't even need to get the body of the request, as you are not using it anyway.
If an item has been deleted from DB, it makes sense to also remove it from your view. You can do so by refreshing the page (not a good idea), by reloading the list or by filtering the array, as in:
removeById = (id) => {
this.setState((state) => ({
pelicula: state.pelicula.filter((item) => item.id !== id)
}));
};
async handleBorrar(id) {
alert(`hello, ${id}`);
try {
const responseDel = await fetch(
`http://localhost/APIpeliculas/api/pelicula/read.php/${id}`,
{
method: "DELETE"
}
);
if (!responseDel.ok) throw new Error("API request not ok");
if (responseDel.status >= 400 && responseDel.status < 600) {
throw new Error("Bad response from server");
}
this.removeById(id);
} catch (error) {
// do something with the error, maybe warn the user
}
}

Combining laravel pagination with live search using ajax

I have a list of projects displayed in a table which has a pagination at the bottom by using laravel's paginatation.
$projects = projects::where('active', '=', 1)->orderBy('id', 'desc')->paginate(15);
return view('index', compact('projects'));
I also have a live search to filter the projects by name, using ajax.
public function search(Request $request){
if($request->ajax()){
$query = $request->get('query');
if($query != ''){
$data = DB::table('projects')
->where('active', '=', 1)
->whereNull('deleted_at')
->where('name', 'like', '%'.$query.'%')
->get();
}else{
$data = DB::table('projects')->where('active', '=', 1)->whereNull('deleted_at')->orderBy('id', 'desc')->get();
}
}
return response($data->jsonSerialize(), Response::HTTP_OK);
}
Js:
searchProjects = function(query){
$.ajax({
url: "/projects/search",
type: "POST",
data: {
query: query,
},
success: function (response){
displayData(response);
}
})
},
So first I load the projects via server side and then if I do a search, the data gets replaced with the result via ajax.
The problem I'm facing is that whenever I do a search, the paginations doesn't update.
Let's say the search displays 5 results, I want the pagination to go from 1-2 to 1-1 or even just disappear (if that makes sense) if there are less than 15 results (for instance).
Does anyone have any idea how I would combine both a live search and a pagination that work together on laravel?
I believe your problem is you want to combine both PHP generated HTML with JS generated HTML.
The paginate part will generate a specific HTML, if you want to update your data without a full reload of the page (via the Ajax call) you need to regenerate the HTML.
You can do this by creating a JS that builds your HTML. However this would mean you have 2 places to maintain your HTML.
I would propose to update your code to (instead of the JSON data) return a newly generated HTML part, and inject this new HTML in your page.
Also be sure to update your search function to make full use of you model instead of using the DB::table.
Hope this response is a bit clear.
Let's say you have a jobs/index.blade.php file. This will act as the base file for your jobs. It will list all the jobs available:
<div class="container">
<div class="row">
<div class="col-sm-9">
#if (count($jobs) > 0)
<section class="jobs">
#include('jobs.load')
</section>
#endif
</div>
<div class="col-sm-3">
</div>
</div>
</div>
<script>
$(function() {
$('body').on('click', '.pagination a', function(e) {
e.preventDefault();
$('#load a').css('color', '#dfecf6');
$('#load').append('<img style="position: absolute; left: 0; top: 0; z-index: 100000;" src="/images/loading.gif" />');
var url = $(this).attr('href');
getJobs(url);
window.history.pushState("", "", url);
});
function getJobs(url) {
$.ajax({
url : url,
success: function(data) {
$('.jobs').html(data);
},
error: function(err) {
alert("jobs cannot be loaded");
console.log(err);
}
});
}
});
</script>
This will be the file component, jobs/load.blade.php that will be requested on the ajax:
<div id="load" style="position: relative;">
#foreach($articles as $article)
<div>
<h3>
{{$article->title }}
</h3>
</div>
#endforeach
</div>
{{ $articles->links() }}
Now to open the page, you will need a controller function, it is self documented:
public function index(Request $request)
{
// get jobs and limit to 5 data
$jobs = Jobs::paginate(5);
// this condition will be executed on the ajax request
// that is everytime you click on prev/ next
// it will be handled by jquery's .html() function
if ($request->ajax()) {
return view('jobs.load', ['jobs' => $jobs])->render();
}
// on traditional HTTP request, it will load the base page
return view('jobs.index', compact('jobs'));
}
Reference:
https://laraget.com/blog/how-to-create-an-ajax-pagination-using-laravel

Updating content Laravel

I want to make a feature for my web app in laravel(i'm new at it) that every Post/Comment/Theme(in my case) the user has the ability to upVote and downVote. Now i am woking with upVote, but it is not working whatsoever.
In the view (welcome.blade.php)
I have:
<img class="media-object" style="height:40px; width:40px;" src="images/upVote.svg" alt="...">
Where $Theme->name is the one that the user wants to upVote/like(whatsoever).
The route:
Route::put('/', [
'uses'=>'Vote#VotePlus',
'as' =>'Voteplus' //Name of route
]);
And the controller:
<?php
namespace App\Http\Controllers;
use App\NewTheme;
use DB;
class Vote extends Controller {
public function VotePlus($name){
DB::table('New_Themes')
->where('name', $name)
->increment('upVotes', 1);
$Themes = NewTheme::paginate(5);
return redirect()->route('welcome', ['Themes'=>$Themes]);
}
};
I am trying everything, but it isn't working. Can someone help me please?
With an anchor tag, you only send a get request. If you want it to be put, you must create a form, and then add :
<input type="hidden" name="_method" value="PUT">
Another way to solve this issue is to use Ajax. Right now the page will get refreshed each time a user wants to up-vote a theme and that can be quite frustrating.
I think you should post to the back end using Ajax and on the success callback update the view with javascript. I recommend using Angular for the front end. It has all what you need and it is super simple to make an Ajax-request.
So, here's a quick example how you could use Angular + Laravel to make your web application work.
Front End
<html ng-app="exampleApp">
<head>
<title>MyTitle</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body>
<div ng-controller="ThemeController">
<ul>
<li ng-repeat="theme in themes">
<span><% theme.name %></span>
<p><% theme.description %></p>
<p><% theme.votes %></p>
Vote Up
</li>
</ul>
</div>
<script type="text/javascript">
var app = angular.module("exampleApp", [], function($interpolateProvider) {
// This we need to not collide with Laravel's {{ }}
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
});
app.controller('ThemeController', function($scope, $http) {
$scope.themes = [];
$scope.voteUp = function(theme) {
$http({
url: '/api/themes/voteUp',
method: 'POST',
data: {
id: theme.id
}
}).success(function(response) {
theme.votes += 1;
});
}
// On init we need to get the themes
$http({
url: '/api/themes',
method: 'GET'
}).success(function(themes) {
$scope.themes = themes;
});
});
</script>
</body>
</html>
Back End
Your routes
Route::get('api/themes', 'ThemeController#getFive');
Route::post('api/themes/voteUp, 'ThemeController#voteUp');
Your ThemeController
function getFive() {
return Theme::paginate(5);
}
function voteUp(Request $request) {
$theme = Theme::whereId($request->id);
$theme->votes += 1;
$theme->save();
return $theme;
}
This code is not tested. But I'll think you get the point!

AngularJS: Handling multiple responses in controller and view

I'm building a news app. User can post different types of news from their home page. Home Page
<uib-tabset active="active">
<uib-tab index="0" heading="All News">
<news-feed poststype="1" username="userName"></news-feed>
</uib-tab>
<uib-tab index="1" heading="Internation">
<news-feed poststype="3" username="userName"></news-feed>
</uib-tab>
<uib-tab index="2" heading="Regional">
<news-feed poststype="7" username="userName"></news-feed>
</uib-tab>
</uib-tabset>
News feed is a directive that I injected in home page.
This is the view: (news feed view)
<div class="post-textarea">
<textarea class="form-control" ng-model="vm.currentPost.content"></textarea>
<a class="btn btn-primary" ng-click="vm.addPost(vm.currentPost.content)">Post</a>
</div>
<div class="clearfix"></div>
<div>
<ul class="media-list">
<li class="media post" ng-repeat="post in vm.posts">
<div class="post-main">
<div class="post-content">{{post.content}}</div>
</div>
</li>
</ul>
</div>
It has a text area using which users can post new news updates. But when a user publishes it, it show reflect in all the three news feeds. because user can set more than one category to a news posts, which I'm not including here to reduce complexity.
But it's not getting reflected in all the three tabs.
This is my controller (news feed controller):
(function() {
angular
.module('myApp.newsFeed', [])
.factory('newsFeedService', function($http) {
var baseUrl = 'api/';
return {
postCurrentPost: function(newPost) {
var dataPost = {
newPost: newPost
};
return $http({
method: 'post',
url: baseUrl + 'postCurrentPost',
data: dataPost,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
};
})
.directive('newsFeed', function() {
var controller = function($routeParams, newsFeedService, $scope, focus) {
var vm = this;
// Add a news post
vm.addPost = function(newPost) {
var currentPost = vm.currentPost;
currentPost.created_at = new Date();
currentPost.content = ""; //clear post textarea
if (newPost) {
newsFeedService.postCurrentPost(newPost).success(function(data) {
vm.posts = data;
});
}
};
};
var template = '<button>{{vm.poststype}}</button>';
return {
restrict: 'E',
scope: {
poststype: '#',
username: '='
},
controller: controller,
controllerAs: 'vm',
bindToController: true, //required in 1.3+ with controllerAs
templateUrl: 'app/newsFeed.html'
//template: template
};
});
})();
But my current setup shows it only in one tab. Or user has to reload the page.
Is there a way to reflect a new change in all the 3 tabs?
My PHP code (backend) looks like this:
function postCurrentPost()
{
$requestData = json_decode(file_get_contents("php://input"));
$newPost = $requestData->newPost;
$content=validate_input($newPost);
//code to save it to db comes here
//fetch all news; I have functions returning international and regional news
//how can I handle it in angular view
$data=getAllPosts();
return $data;
}
function getAllPosts()
{
//returns all news
}
function international()
{
//returns international news
}
function regional()
{
//returns regional news
}
Since it's a directive that I injected to home page, and all the three tabs share the same page code, how can I do this?
Since you are wanting to share one model you can create a controller for the main view and define the model which I just named newsData:
Home Page Controller
.controller('MainCtrl', function() {
var vm = this;
vm.newsData = [{
id: 1,
type: 1,
content: 'first post'
}];
});
This model will be passed into your directive via an attribute called news-data
Home Page
<body ng-controller="MainCtrl as main">
<uib-tabset active="active">
<uib-tab index="0" heading="All News">
<news-feed poststype="1" username="userName" news-data="main.newsData"></news-feed>
</uib-tab>
<uib-tab index="1" heading="Internation">
<news-feed poststype="3" username="userName" news-data="main.newsData"></news-feed>
</uib-tab>
<uib-tab index="2" heading="Regional">
<news-feed poststype="7" username="userName" news-data="main.newsData"></news-feed>
</uib-tab>
</uib-tabset>
</body>
Now anything that you want shared in your directive controller, including the newsData array, needs to be passed in via bindToController rather than into the isolate scope of the directive
newsFeed Directive
return {
restrict: 'E',
scope: {
username: '='
},
controller: controller,
controllerAs: 'vm',
bindToController: {
poststype: '#',
newsData: '='
}, //required in 1.3+ with controllerAs
templateUrl: 'app/newsFeed.html'
//template: template
};
Now in your directive controller you can access the shared members, including newsData
newsFeed Directive Controller
vm.addPost = function(newPost) {
var currentPost = vm.currentPost;
currentPost.created_at = new Date();
currentPost.content = ""; //clear post textarea
console.log(vm);
if (newPost) {
var postToAdd = {
type: vm.poststype,
content: newPost
};
newsFeedService.postCurrentPost(postToAdd).then(function(data) {
vm.newsData = data;
});
}
};
So there's the explanation, but here it is in action.

Showing live CPU usage via WMI with PHP and Ajax

Is there any alternative to a persistent connection with just Apache/PHP than setting up another server with WebSockets/Node.js?
At the current moment, I'm running a typical WAMP server with a Laravel application. This laravel application is a sort of dashboard app which can show details (such as CPU/Network usage) of our servers on the network. This application will only be used by a couple of people at a time (it's internal) so it allows me to be quite flexible with performance.
I'm using the COM library in PHP to query the server for information via WMI. I have it set up by using a typical GET route that returns a json string of the CPU usage in percentage of the server from WMI. This is getting refreshed every single second using setInterval().
Though obviously this is immense load on the server, and CPU goes through the roof when seeing the usage of a network PC.
A picture is below showing what my app looks like. The progress bar will fill to the percentage returned when the ajax request completes. It looks good and works well, but I feel like running an ajax request every single second is bad design, and really want something that can just constantly feed the progress bar rather than request a new value from the server.
Please let me know if you need any code/examples of my current progress. Thanks!
Code as requested:
My route:
Route::get('{machine_id}/{field?}', array('as'=>'admin.computer.view.detailed', 'uses'=>'ComputerController#getViewDetailed'));
My Controller:
public function getViewDetailed($computer_id, $field = NULL){
$computer = $this->machine->find($computer_id);
if($computer){
if(!$computer->type->type_name == 'Servers'){
return Redirect::route('admin.computer.index');
} else{
if($field){
switch($field){
case 'cpu':
return Response::json(Network::get_cpu_info($computer->machine_name));
break;
case 'temp':
return Response::json(Network::get_temp_info($computer->machine_name));
break;
case 'tcp':
return Response::json(Network::get_tcp_info($computer->machine_name));
break;
}
}
$disks = Network::get_disk_info($computer->machine_name);
$memory = Network::get_memory_info($computer->machine_name);
$cpu = Network::get_cpu_info($computer->machine_name);
$tcp = Network::get_tcp_info($computer->machine_name);
$this->layout->title = 'Viewing Server Details for: '.$computer->machine_name;
$this->layout->content = View::make('computers.templates.view.detailed')
->with('computer', $computer)
->with('disks', $disks)
->with('memory', $memory)
->with('cpu', $cpu)
->with('tcp', $tcp);
}
} else{
return Redirect::route('admin.computer.index')
->with('message', Lang::get('custom.messages.computers.errors.exist'))
->with('color','danger');
}
}
My class requesting WMI Information:
class Cpu {
public static $com_namespace = 'root\\cimv2';
private $query = 'SELECT Name, CurrentClockSpeed, LoadPercentage From Win32_Processor';
private $cpu = array();
public function info($service, $pc){
$this->cpu = $service->ExecQuery($this->query);
return $this->format($this->cpu);
}
public function format($cpu){
$formatted_cpu = array();
$i = 0;
foreach($cpu as $entry){
$formatted_cpu[$i]['name'] = $entry->Name;
$formatted_cpu[$i]['current_clock_speed'] = $entry->CurrentClockSpeed;
$formatted_cpu[$i]['load'] = $entry->LoadPercentage;
$i++;
}
return $formatted_cpu;
}
}
My View:
#if($cpu)
<script type='text/javascript'>
$(document).ready(function(e) {
function getCpu(){
$('.server').each(function(index, element) {
var server = $(this);
var url = $(this).attr('data-url');
var panel = $(this).find('.panel');
var progress_bar = $(this).find('.progress-bar');
$.ajax({
url: url,
type: 'GET',
dataType:"json",
success: function(response){
if(response){
$(progress_bar).html(response[0]['load']+"%").attr('aria-valuenow', response[0]['load']).css('width', response[0]['load']+"%");
if(response[0]['load'] > 50){
$(panel).removeClass('panel-default').addClass('panel-danger');
} else{
$(panel).removeClass('panel-danger').addClass('panel-default');
}
} else{
$(server).css('display', 'none');
}
}
});
});
}
setInterval(getCpu, 1000);
});
</script>
<div data-url="{{ route('admin.computer.view.detailed', array($computer->id, 'cpu')) }}" class="server">
<div class="panel panel-default">
<div class="panel-heading text-center">CPU Load</div>
<div class="panel-body">
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
</div>
</div>
</div>
</div>
</div>
#endif

Categories