How to fetch single data in Angularjs with Laravel5 - angularjs

I face an issue while retrieving single row/data from angular to html. I need to print the title. Below is the code of angular controller (partial):
vm.showJoke = function(joke){
console.log(joke);
$http.get('http://localhost:8000/api/v1/jokes/' + joke, {
//body: joke.joke,
//user_id: $rootScope.currentUser.id
//user_id: localstorageUser.role_id
}).success(function(response) {
//console.log(response.data.joke);
vm.jokes_show = response.data.joke;
console.log(vm.jokes_show);
$scope.MessageAll = 'Joke shows! ';
}).error(function(){
console.log("error");
$scope.MessageAll = 'Please try again';
});
}
Below is my HTML codes:
<span ng-hide="showEnabled">
<span class="glyphicon glyphicon-th-large" data-ng-click="jokes.showJoke(joke.joke_id)"></span>
</span>
<span ng-show="showEnabled" style="background-color:powderblue;">
<p style="background-color:powderblue;" ng-model="jokes_show"></p>
</span>
Here is the response I found below:
{joke_id: 3, joke: "Quia in enim voluptates neque. Ullam eligendi ipsu…iente qui perferendis libero. Ut aut qui sint et.", submitted_by: "admin"}
joke
:
"Quia in enim voluptates neque. Ullam eligendi ipsum eaque magni sit fugit in. Voluptate sapiente qui perferendis libero. Ut aut qui sint et."
joke_id
:
3
submitted_by
:
"admin"
See the image for the same too.
Your help most welcome.

Related

How to target a specific element in react map loop

I have comments that i loop through:
When i click on the three dots i want there to pop a little div out with the text "repport comment".
But when i click on one of buttons they all open :
import { FaEllipsisV } from "react-icons/fa";
import "./styles.css";
import React from "react";
const data = [
{
postId: 1,
id: 1,
name: "id labore ex et quam laborum",
email: "Eliseo#gardner.biz",
body:
"laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium"
},
{
postId: 1,
id: 2,
name: "quo vero reiciendis velit similique earum",
email: "Jayne_Kuhic#sydney.com",
body:
"est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et"
},
{
postId: 1,
id: 3,
name: "odio adipisci rerum aut animi",
email: "Nikita#garfield.biz",
body:
"quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione"
},
{
postId: 1,
id: 4,
name: "alias odio sit",
email: "Lew#alysha.tv",
body:
"non et atque\noccaecati deserunt quas accusantium unde odit nobis qui voluptatem\nquia voluptas consequuntur itaque dolor\net qui rerum deleniti ut occaecati"
},
{
postId: 1,
id: 5,
name: "vero eaque aliquid doloribus et culpa",
email: "Hayden#althea.biz",
body:
"harum non quasi et ratione\ntempore iure ex voluptates in ratione\nharum architecto fugit inventore cupiditate\nvoluptates magni quo et"
}
];
export default function App() {
const [showOptions, setShowOptions] = React.useState(false);
return (
<div className="App">
{data.map((comment, index) => (
<div key={index} className="comment-container">
{comment.name}
<button onClick={() => setShowOptions(!showOptions)}>
<FaEllipsisV />
</button>
{showOptions ? (
<div className="options">Report this comment</div>
) : null}
</div>
))}
</div>
);
}
https://codesandbox.io/s/elated-roentgen-fbjr7?file=/src/App.js:0-2121
Example of what i'd like :
You can do something like this:
export default function App() {
const [showOptions, setShowOptions] = React.useState({ id: null, status: false });
return (
<div className="App">
{data.map((comment, index) => (
<div key={index} className="comment-container">
{comment.name}
<button onClick={() => setShowOptions({ id: comment.id, status: !showOptions.status })}>
<FaEllipsisV />
</button>
{showOptions.status && comment.id === showOptions.id ? (
<div className="options">Report this comment</div>
) : null}
</div>
))}
</div>
);
}

In Angular JS, is there a way to watch for changes to the DOM without using scope.watch?

I am attempting to create an angularjs bootstrap accordion that scrolls the accordion to the top when opened.
These solutions are close to what I would like to do:
AngularJS / ui-bootstrap accordion - scroll to top of active (open) accordion on click
https://www.peterbouda.eu/making-an-angular-ui-bootstrap-accordion-scrolling-to-top-when-opening.html
However, they use a timeout or scope watches. I would like to avoid using these unless absolutely necessary.
Is there a way to accomplish this without using $watch or setTimeout?
Here is a plunk of what i am trying to do, this is using the $watch: https://plnkr.co/edit/XQpUdrdjqaCGom4L9yIJ
app.directive( 'scrollTop', scrollTop );
function scrollTop() {
return {
restrict: 'A',
link: link
};
}
function link( scope, element ) {
scope.collapsing = false;
var jqElement = $( element) ;
scope.$watch( function() {
return jqElement.find( '.panel-collapse' ).hasClass( 'collapsing' );
}, function( status ) {
if ( scope.collapsing && !status ) {
if ( jqElement.hasClass( 'panel-open' ) ) {
$( 'html,body' ).animate({
scrollTop: jqElement.offset().top - 30
}, 500 );
}
}
scope.collapsing = status;
} );
}
The directive can be simplified to:1
app.directive( 'scrollTop', function scrollTop($timeout) {
return {
restrict: 'A',
link: postLink
};
function postLink(scope, elem, attrs) {
elem.on("click", function(e) {
if (scope.status.isOpen) {
$timeout(function() {
$( 'html,body' ).animate({
scrollTop: elem.offset().top - 30
}, 500 );
});
}
});
}
})
<uib-accordion>
<div heading="Section Title" is-open="status.isOpen"
ng-repeat="section in vm.sections"
scroll-top
uib-accordion-group>
<uib-accordion-heading>
<div ng-class="{isOpen: vm.isOpen}">
<h3>{{section.sectionTitle}}</h3>
<p>{{section.sectionSubHeader}}</p>
</div>
</uib-accordion-heading>
<div class="clearfix">
<b>Index+1={{$index+1}}</b>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</div>
</uib-accordion>
The $timeout is necessary because the browser needs to render the DOM with the newly opened and closed elements before it can compute the proper scroll offset.
The DEMO on PLNKR
I have found a way to do this from the controller.
I added a function that is triggered on ng-click to report the is-open status of the accordion.
Using the component lifecycle hook $doCheck I was able to watch for changes to the state of vm.isOpen. $doCheck runs on the end of every digest cycle, so I did not need to set a $scope.watch or $timeOut
The $doCheck runs essentially the same code as the directive in the question
app.controller('homeController', function($state, $element, sections, $transitions) {
var vm = this;
vm.$onInit = function() {
vm.sections = sections.getSections();
};
function updateOpenStatus() {
vm.collapsing = false;
vm.isOpen = vm.sections.some(function(item) {
return item.isOpen;
});
}
vm.$doCheck = function() {
if (vm.isOpen) {
var elem = $element.find('.panel-collapse');
var status = elem.hasClass('collapsing');
if (vm.collapsing && !status) {
var parentElem = elem.closest('.panel-open');
if (elem.parent().hasClass('panel-open')) {
$('html,body')
.stop()
.animate({
scrollTop: parentElem.offset().top - 52
}, 'fast');
}
}
vm.collapsing = status;
}
};
});
I updated the uib-accordion to call the function in the controller
<uib-accordion>
<div heading="Section Title" is-open="section.isOpen" ng-repeat="section in vm.sections" scroll-top uib-accordion-group>
<uib-accordion-heading>
<div ng-class="{isOpen: section.isOpen}" ng-click="vm.toggleOpen()">
<h3>{{section.sectionTitle}}</h3>
</div>
</uib-accordion-heading>
<div class="clearfix">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</div>
</uib-accordion>
Updated Plnkr: https://plnkr.co/edit/5EqDfmVOa0hzFfaQqdI0?p=preview

Api-platform accessing embedded relations in hydra:member

I'm using Api-Platform and React as client.
I have a Forum entity which contains other objects : an author (User entity) and a category (Category entity).
I embedded these entities with #Groups annotations to retrieve them more easily.
For instance, when I fetch /api/forums/ on Postman I get this result :
{
"#context": "/api/contexts/Forum",
"#id": "/api/forums",
"#type": "hydra:Collection",
"hydra:member": [
{
"#id": "/api/forums/79",
"#type": "Forum",
"id": 79,
"subject": "Sujet numéro 0",
"message": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"category": {
"#id": "/api/categories/183",
"#type": "Category",
"title": "Category 2"
},
It seems good : we can see my category object is linked to Forum in hydra:member array, and a "title" field.
But I noticed that the result I really get is different in my react app for all my nested objects.
I only get the IRIs..
For instance with the same request :
...
fetch('forums')
.then(response =>
response
.json()
.then(retrieved => ({ retrieved, hubURL: extractHubURL(response) }))
)
.then(({ retrieved, hubURL }) => {
retrieved = normalize(retrieved);
...
I get this result :
{
"#context": "/api/contexts/Forum",
"#id": "/api/forums",
"#type": "hydra:Collection",
"hydra:member": [
{
"#id": "/api/forums/79",
"#type": "Forum",
"id": 79,
"subject": "Sujet numéro 0",
"message": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"category": "/api/categories/183",
Every other fields have disapeared on "category", and I don't get why.
Could anyone help me with that ?
Thanks in advance
I found the solution (how silly of me), so I share you the tip :
In src/utils/dataAccess file, there is a normalize function :
export function normalize(data) {
if (has(data, 'hydra:member')) {
// Normalize items in collections
data['hydra:member'] = data['hydra:member'].map(item => normalize(item));
return data;
}
// Flatten nested documents
return mapValues(data, value =>
Array.isArray(value)
? value.map(v => get(v, '#id', v))
: get(value, '#id', value)
);
}
It appears that this function is called after each fetch :
return fetch(id)
.then(response =>
response
.json()
.then(retrieved => ({ retrieved, hubURL: extractHubURL(response) }))
)
.then(({ retrieved, hubURL }) => {
//retrieved = normalize(retrieved);
dispatch(loading(false));
dispatch(success(retrieved));
....
As you can see, I just commented the normalize line (useless in my case). Do that wherever it is needed, and everything should work again !

How to call single api in multiple react component with mixed up server side code?

Below is my nested object json, where i want access the properties in different react component
{
"Created":"2017-02-09",
"SenderOrReceiver":"Not developed yet",
"PageResponsible":"Yogesh Shinde",
"LastUpdated":"2017-02-09",
"ExternalLinks":[
{
"Id":null,
"Title":"Yahoo",
"Url":"http://yahoo.com"
},
{
"Id":null,
"Title":"Facebook",
"Url":"http://facebook.com"
}
],
"InternalLinks":[
{
"Id":null,
"Title":"Google",
"Url":"~/link/23199285feef4501987b5fa452e49b94.aspx"
}
],
"Appendices":[
{
"Id":null,
"Title":"React",
"Url":"~/link/23199285feef4501987b5fa452e49b94.aspx"
}
],
"ContactDetails":{
"Email":"user#gmail.com",
"Information":"Aliquam mollis, quam nec suscipit placerat, nibh est efficitur urna, in ornare mauris eros eu tortor. Nulla fermentum hendrerit mi, nec luctus nunc auctor at. Nullam sagittis posuere libero, eget imperdiet neque. Etiam ac lacus diam. Mauris sapien turpis, lobortis non eros in, porttitor dapibus ipsum.",
"Name":"user1",
"Telephone":"11234"
},
"Subject":[
"Lorem"
],
"HeadingLinks":[
{
"Id":"headinglink1",
"Title":"Heading1",
"Url":"/sv/news-page/#headinglink1"
}
]
}
Below is my server side index.cshtml (Layout)
#model intrav2.infrastructure.ViewModels.Pages.NewsPageViewModel
<div class="l-content_primary" role="main">
<div id="breadcrumb"></div>
<h2>#Html.PropertyFor(x => x.CurrentPage.Heading)</h2>
<div id="newcreatedinfo"></div>
<div>#Html.PropertyFor(x => x.CurrentPage.Media)</div>
<p class="preamble">#Html.PropertyFor(x => x.CurrentPage.Preamble)</p>
<div id="newsHeadingLinks"></div>
<p>#Html.PropertyFor(x => x.CurrentPage.MainBody)</p>
#Html.PropertyFor(x => x.CurrentPage.ExtraInformation)
<div id="newspagecontent"></div>
</div>
<aside class="l-blocks_secondary" role="complementary" id="newsSiderBar"></aside>
Now i want,
Created/SenderOrReceiver property in newcreatedinfo
External and Internal links in newspagecontent
Appendices/Contact in side content on page

why does angular directive disable text filter?

I am adding a readmore directive to an angular app. The read-more works great, but try to use a filter for text and it does not interpret the filter string correctly.
Example: http://plnkr.co/edit/Tsqkv1nd6CC8e5Kr9pdU?p=preview
Change demo text to the code below to see what is happening:
<p read-more>(1) This is a short paragraph.</p>
<p read-more>(2) This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph.</p>
<p>(3) {{desc}}</p>
<p read-more>(4) {{desc}}</p>
Notice the 3rd and 4th examples use the $scope.desc value defined in the controller in app.js. #3 works. #4 fails. Why? How to fix?
app.js:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.desc = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec rutrum vehicula tortor, vitae ornare nunc semper eu. Vivamus varius, eros vel tristique accumsan, libero nulla cursus ante, eu eleifend risus orci scelerisque nibh. Curabitur feugiat, augue ut commodo bibendum, nisi leo porttitor diam, tincidunt auctor tellus ante sit amet nibh. Duis velit libero, aliquam at felis eu, pellentesque mollis mi. Nam a est orci. Ut bibendum sagittis semper. Cras eget arcu non augue mollis aliquam. Ut ut gravida ligula. Nulla imperdiet lacinia mi, nec fringilla mauris interdum at. Phasellus gravida tempor varius. Cras molestie et nulla eget maximus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris aliquet malesuada feugiat. Curabitur fermentum bibendum nulla, non dictum ipsum tincidunt non. Quisque convallis pharetra tempor. Donec id pretium leo. Pellentesque luctus massa non elit viverra pellentesque. Cras vitae neque molestie, rhoncus ipsum sit amet, lobortis dui. Fusce in urna sem. Vivamus vehicula dignissim augue et scelerisque. Etiam quam nisi, molestie ac dolor in, tincidunt tincidunt arcu. Praesent sed justo finibus, fringilla velit quis, porta erat. Donec blandit metus ut arcu iaculis iaculis. Cras nec dolor fringilla justo ullamcorper auctor. Aliquam eget pretium velit. Morbi urna justo, pulvinar id lobortis in, aliquet placerat orci.';
});
app.directive('readMore', function() {
return {
restrict: 'A',
transclude: true,
replace: true,
template: '<p></p>',
scope: {
moreText: '#',
lessText: '#',
words: '#',
ellipsis: '#',
char: '#',
limit: '#',
content: '#'
},
link: function(scope, elem, attr, ctrl, transclude) {
var moreText = angular.isUndefined(scope.moreText) ? ' <a class="read-more">Read More...</a>' : ' <a class="read-more">' + scope.moreText + '</a>',
lessText = angular.isUndefined(scope.lessText) ? ' <a class="read-less">Less ^</a>' : ' <a class="read-less">' + scope.lessText + '</a>',
ellipsis = angular.isUndefined(scope.ellipsis) ? '' : scope.ellipsis,
limit = angular.isUndefined(scope.limit) ? 150 : scope.limit;
attr.$observe('content', function(str) {
readmore(str);
});
transclude(scope.$parent, function(clone, scope) {
readmore(clone.text().trim());
});
function readmore(text) {
var text = text,
orig = text,
regex = /\s+/gi,
charCount = text.length,
wordCount = text.trim().replace(regex, ' ').split(' ').length,
countBy = 'char',
count = charCount,
foundWords = [],
markup = text,
more = '';
if (!angular.isUndefined(attr.words)) {
countBy = 'words';
count = wordCount;
}
if (countBy === 'words') { // Count words
foundWords = text.split(/\s+/);
if (foundWords.length > limit) {
text = foundWords.slice(0, limit).join(' ') + ellipsis;
more = foundWords.slice(limit, count).join(' ');
markup = text + moreText + '<span class="more-text">' + more + lessText + '</span>';
}
} else { // Count characters
if (count > limit) {
text = orig.slice(0, limit) + ellipsis;
more = orig.slice(limit, count);
markup = text + moreText + '<span class="more-text">' + more + lessText + '</span>';
}
}
elem.append(markup);
elem.find('.read-more').on('click', function() {
$(this).hide();
elem.find('.more-text').addClass('show').slideDown();
});
elem.find('.read-less').on('click', function() {
elem.find('.read-more').show();
elem.find('.more-text').hide().removeClass('show');
});
}
}
};
});
style.css:
/* Put your css in here */
a.read-more, a.read-less {
cursor: pointer;
color: blue;
font-size: 0.8em;
}
span.more-text {
display: none;
}
span.more-text.show {
display: inline !important
}
index.html:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>Angular Read More Directive</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="jquery" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script data-require="angular.js#1.3.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js" data-semver="1.3.7"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p read-more>This is a short paragraph.</p>
<p read-more>This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph. This is a long paragraph.</p>
<p read-more>{{desc}}</p>
</body>
</html>
As per your current code implementation readmore is getting called before the transcluded DOM content gets projected on directive template.
In this case you should take use content attribute just by saying content="{{desc}}", which will allow to call readmore method of directive as attr.$observe method will get fired.
<p read-more content="{{desc}}">(4)</p>
Demo Plunkr

Resources