AngularJS: Handling multiple responses in controller and view - php

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.

Related

Laravel Ajax Pagination: No request

I have some difficulties with my ajax pagination linked to a filter. Here's how it should work. The user can access via a specific page to a form. When clicking the submit button, a raw sql request is made in JS and a POST ajax request is achieved to get the results at the bottom of the page with a pagination menu. This part works. But I have some issues with the pagination menu because the links don't work. For example, by clicking the "page 2" link, nothing happens.
Here are the different parts of my code:
Routes
Route::get('articles/filter', 'ArticleController#filterx');
Route::post('articles/request/ajax/articles/filter', 'ArticleController#filtery');
Route::get('articles/request/ajax/articles/filter', 'ArticleController#filtery');
Controller
ArticleController
public function filterx() { // get filter page
return view('filter');
}
public function filtery(Request $request) { // filter ajax function
$articles = Article::paginate(2);
if($request->ajax()) {
// partial view returned in html
return $html = view('filterResults', compact('articles'));
}
}
Views
filter.blade.php
#extends('layouts/app')
#section('title')
Title
#endsection
#section('content')
<div class="container">
<!-- filter -->
<h2>Filter</h2>
<div class="content-card content">
<form method="POST" action="">
<!-- form code... -->
</form>
</div>
<div id="filter-results">
</div>
</div>
#endsection
filterResults.blade.php
#foreach($articles as $article)
<p>{{ $article->name }}</p>
#endforeach
{{ $articles->links() }}
Javascript
$("#submit-button").click(function(e) {
e.preventDefault();
// ajax request (raw mysql request)
var requestQuery = ...; // (quite long) raw request
console.log(requestQuery); // console verification of request
$.ajax({
headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
url: '../articles/request/ajax/articles/filter',
type: 'POST',
data: {
request: requestQuery
},
success: function(html) {
$("#filter-results").empty().html(html);
}
});
});
$(window).on('hashchange', function() {
// if hash in url
if (window.location.hash) {
// page contains hash value
var page = window.location.hash.replace('#', '');
if (page == Number.NaN || page <= 0) {
return false;
}
// if ok ->getData returned
else {
getData(page);
}
}
});
$(document).on('click', '.pagination a', function(e) {
e.preventDefault();
$('.pagination li').removeClass('active');
$(this).parent('li').addClass('active');
var url = $(this).attr('href');
var page = $(this).attr('href').split('page=')[1];
getData(page,url);
});
function getData(page,url) {
$.ajax(
{
url: url,
type: 'get',
datatype: 'html',
done: function(data) {
console.log('ok');
$('#filter-results').empty().html(data);
location.hash = page;
},
fail: function(jqXHR, ajaxOptions, thrownError) {
console.log('No response from server');
}
});
}
I don't understand why it is not working, I thing I misunderstood something.
Thanks and have a good day
Laravel uses the page value from the request, or query string, by convention. If you choose not to use that, you can set your own. If following convention, you'd need to append the query string page=# to your url in the ajax request.
The fourth argument of the Builder::paginate is the page number:
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $this->model->getPerPage();
$results = ($total = $this->toBase()->getCountForPagination())
? $this->forPage($page, $perPage)->get($columns)
: $this->model->newCollection();
return $this->paginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
You could also define your own page resolver. The default is set in PaginationServiceProvider:
Paginator::currentPageResolver(function ($pageName = 'page') {
$page = $this->app['request']->input($pageName);
if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
return (int) $page;
}
return 1;
});
Route::get('articles/filter/{page}', 'ArticleController#filter');
public function filter(Request $request, int $page) {
$articles = Article::paginate($page);
}
it's all

Laravel how to pass data from controller to modal dialogue using ajax

I have items and for every item there are related items, so when I open the homepage it shows all item, when I want to click on any item, ajax will pass this item id to controller to get the related items for this item, the problem is I want to show the related item in a modal dialogue, the modal dialogue now show all related items to all items not to the current item.
I think the problem is because the include of modal in the homepage which has the foreach!, hope you can help me in solving this issue
route
Route::get('/',['as'=>'showItems','uses'=>'HomeController#getItem']);
Route::get('Get_relateditem',['as'=>'Get_relateditem','uses'=>'HomeController#getItem']);
ajax
$(function(){
$('.Item_root').on("click", function () {
var item_id = $(this).data('id');
$.ajax({
type:'get',
url: '/',
data: {
'_token': $('input[name=_token]').val(),
'item_id':item_id,
},
success:function(data){}
});
});
});
controller
public function getItem(Request $request)
{
$currentitemid =$request->item_id;
$ritems = Relateditem::orderBy('id', 'asc')->where('ritemf_id','LIKE','%'.$currentitemid.'%')->with('items')->get()->groupBy('ritemf_id');
$items = Item::orderBy('category_id', 'asc')->with('category')->get()->groupBy('category_id');
$categories = Category::orderBy('category_id', 'asc')->get();
return view('home')->with('items',$items)->with('categories',$categories)->with('ritems',$ritems);
}
}
modal
#foreach($ritems as $item_id => $realtedItems)
#foreach($realtedItems as $ritem)
<div class="SuggestedItem_container">
<label color="red" class="Checker_root Checker_red Checker_left">
<input type="checkbox" class="Checker_input" value="on">
<div class="SuggestedItem_nameContainer">
<div>
<span class="SuggestedItem_name">{{$ritem->riteml_id}}</span>
<span class="SuggestedItem_price styles_small styles_base styles_spacing-base">+$3.95</span></div></div>
<div class="SuggestedItem_description styles_small styles_base styles_spacing-base">
<span class="SuggestedItem_category styles_bold">Appetizers</span>
<span> ยท Edamame soybean pods harvested right before the beans begin to harden are lightly boiled and seasoned with sea salt.</span>
</div>
</label>
</div>
#endforeach
#endforeach
Modify routes:
Route::get('/','HomeController#getItem');
Route::get('/get_related_items/{id}','HomeController#getRelatedItems');
modify getItem to get only the items and categories:
public function getItem(Request $request)
{
$items = Item::orderBy('category_id', 'asc')
->with('category')->get()
->groupBy('category_id');
$categories = Category::orderBy('category_id', 'asc')->get();
return view('home',['items' => $items,'categories' => $categories]);
}
get related items for a single item id:
public function getRelatedItems(Request $request, $id)
{
$ritems = Relateditem::orderBy('id', 'asc')
->where('ritemf_id',$id)
->with('items')
->get()
->groupBy('ritemf_id');
return response()->json($ritems);
}
now for the js part:
$(function(){
$('.Item_root').on("click", function () {
var item_id = $(this).data('id');
$.ajax({
type:'get',
url: '/get_related_items/' + item_id,
data: {
'_token': $('input[name=_token]').val()
},
success:function(data){
if(data && data.length){
var con_el = $('.SuggestedItem_container');
for(var i = 0; i < data.length;i++){
var related_item_el = "<div class='related_item'><p>" + data[i].id + "</p></div>"
con_el.append(related_item_el);
}
}else{
console.log('no related items found');
}
}
});
});
});
this will insert all the related items inside the SuggestedItem_container
i didn't write the view template cuz that part is easy, and note that i only included the related item id as example cuz i don't know what fields the item has.
i hope this helps you

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!

How to open category to get list of post [ionic & angularjs]

I am creating a hybrid android app using wordpress json api, ionic and angularjs. I am stuck at just one thing : I am unable to list the posts in a particular category.I got the list of categories but unable to pass some parameters. Here's the code
controller.js
var app = angular.module('tsApp', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
views: {
home: {
templateUrl: 'index.html',
controller: 'TSController'
}
}
})
.state('category', {
url: '/category/:slug',
params: {
category: null //stores everything of catergory: slug, name etc.
},
views: {
category: {
templateUrl: 'category.html',
controller: 'CatsPostsCtrl'
}
}
});
$urlRouterProvider.otherwise('/');
})
// Home Controller
app.controller('TSController', function($scope, $http) {
$scope.categories = [];
$http.jsonp('http://localhost/khaliddev/azkarserv/api/get_category_index?callback=JSON_CALLBACK')
.success(function (data1) {
//console.log(data1);
$scope.categories = data1.categories; // response data
//console.log( $scope.categories);
}).error(function (data1) {
//console.log("BLOG failed");
});
});
// Cat Controller
app.controller('CatsPostsCtrl', function($scope, $http, $stateParams) {
console.log($stateParams);
// You can change this url to experiment with other endpoints
//http://localhost/khaliddev/azkarserv/api/?json=get_category_posts&slug=azkar-for-morning&status=publish
var postsApi = 'http://localhost/khaliddev/azkarserv/api/?json=get_category_posts&slug=' + $stateParams.slug + '&status=publish=JSON_CALLBACK';
$scope.category = $stateParams.category.name;
// This should go in a service so we can reuse it
$http.jsonp( postsApi, {cache:true} ).
success(function(data, status, headers, config) {
$scope.posts = data;
console.log( data );
}).
error(function(data, status, headers, config) {
console.log( 'Post load error.' );
});
});
The TSController display all categories but CatsPostsCtrl should display all posts in category which it doesn't. its show me in consle (Error 404), Any help is appreciated. Thanks!
index.html :
<div class="page-content">
<nav class="dashboard-menu">
<div class="row text-center" >
<div class="col-33" ng-repeat="cat in categories">
<a href="category/{{cat.slug}}" class="menu-link">
<span class="icon-folder-plus"></span>
<span>{{cat.title}}</span>
</a>
</div>
</div>
</nav>
</div>
i think you have an error here, maybe you forgot "&callback="
&status=publish=JSON_CALLBACK
Do you know that when you use JSONP your json should be wrapped ?
wikipedia JSONP
I had the same problem once, the URL was good, the preview of chrome was showing me the correct JSON but the status was 404. When i wrapped the json around angular.callbacks._0() it worked
If you have a back-end service, I would advice you to simply use "$http.get" or "$http.post"

Yii, Backbone save(), data did not passed through $_POST

This is my JavaScript in index.php:
MyModel = Backbone.Model.extend({
defaults: {
myID: "",
myName: ""
},
urlRoot: 'testAjaxAdd',
sync: function(method, model, options) {
options = options || {};
options['data'] = {};
options.data["myID"] = model.get("myID");
options.data["myName"] = model.get("myName");
options.data = JSON.stringify(options.data);
return Backbone.sync.apply(this, arguments);
}
});
MyView = Backbone.View.extend({
el: '.page',
render: function(){
var template = _.template($('#add-owner-template').html(), {});
this.$el.html(template);
},
events: {
'submit .create-owner-form': 'saveOwner'
},
saveOwner: function(events) {
var myName= $('input#myName').val();
var owner = new MyModel({
'myID': "111",
'myName': myName
});
owner.save({},{
success: function(model, response, options) {
console.log('success');
console.log(response); // show $_POST from actionSaveOwner in Controller
console.log(model.toJSON()); // show model
console.log(model.get('myID')); // show owner dbcID
console.log(model.get('myName')); // show owner userID
console.log(JSON.stringify(options)); // show options
console.log(options.data["myID"]); // this is shown undefined in console
console.log(options.data["myName"]); // this is shown undefined in console
},
error: function(model, response, options) {
console.log('error');
console.log(response);
console.log(model.toJSON());
}
});
}
});
I have put the code below in very first line within my javascript codes:
Backbone.emulateHTTP = true;
This is my html part of the form, it also a javascript template:
<script type="text/template" id="add-owner-template">
<form class='create-owner-form'>
<label>Name</label>
<input type="text" name="myName" id="myName"/>
<button type="submit" class="btn createcontbutton">Create</button>
</form>
</script>
This is my very simple action in Controller to test out if my backbone works or not:
public function actionTestAjaxAdd()
{
header('Content-type: application/json');
echo CJSON::encode($_POST);
}
However, this is what I see from console in POST tab:
Parameters application/x-www-form-urlencoded Do not sort
{"myID":"111","myName":"i...
But, the $_POST in controller action is nothing when i display it back in console from response.
I finally solved this myself using file_get_contents("php://input") .

Categories