I have done this before but I can't for the life of me remember how. I want a user to be able to select a product by clicking a button in an <li> then have that passed to an array. As well as that, the <li> needs to have a class 'active' once that item is in the selected array:
<li class="row" data-ng-repeat="product in products">
<div class="col-lg-9">
<h3>{{product.name}}</h3>
<p>{{product.description}}</p>
</div>
<div class="col-lg-3">
<button class="btn btn-primary" data-ng-click="selectProduct(product.id)">Select Product</button>
</div>
</li>
is the HTML and this is the controller:
app.controller("MainController", function($scope, $http) {
$scope.selected_products = []
$scope.products = [
{
name: 'Example product',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Id, assumenda, dolor, ipsa, atque obcaecati tempora perspiciatis earum vitae amet cum nostrum blanditiis ducimus culpa molestiae temporibus porro debitis voluptatibus libero.',
category: 'VT'
},
{
name: 'Example product 2',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Id, assumenda, dolor, ipsa, atque obcaecati tempora perspiciatis earum vitae amet cum nostrum blanditiis ducimus culpa molestiae temporibus porro debitis voluptatibus libero.',
category: 'VT'
}
]
$scope.selectProduct = function(name) {
console.log(name)
}
})
Does anyone have any pointers as to how to do this?
Here you are:
$scope.isSelected = function(product){
return this.selected_products.indexOf(product)>-1;
}
$scope.selectProduct = function(product) {
if(!this.isSelected(product)){
this.selected_products.push(product);
}
}
Use it like:
<button ng-disabled="isSelected(product)" data-ng-click="selectProduct(product)">Select Product</button>
Working example: http://plnkr.co/edit/sPAN36?p=preview
Related
I'm stuck. So what do I want from my app:
to animate sections with left fading and opacity (0 to 1) when I scroll down or up.
reuse this component later with different separate components.
What I have now:
Js function that perfectly works with simple HTML and CSS.
nothing from my 'want list'
Please help!
My code is next:
import React from 'react';
const TestAnimation = () => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('.opacity-100');
} else {
entry.target.classList.remove('.opacity-100');
}
});
});
const hiddenElements = document.querySelectorAll('.opacity-0');
hiddenElements.forEach((el) => {
observer.observe(el);
});
return (
<div className='m-0 bg-slate-900 p-0 text-white'>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h1>Test</h1>
</section>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h2>This is first page</h2>
<p>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Autem modi voluptatem est iste a commodi
nesciunt saepe quisquam id dignissimos odit, repellat asperiores laboriosam quibusdam expedita
itaque blanditiis eos pariatur.
</p>
</section>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h2>This is third page</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur veniam sint illo quas beatae,
eum omnis, deleniti error, eveniet praesentium fugiat quia quod? Maxime, placeat reiciendis ab
debitis exercitationem nemo. Laborum perspiciatis eum architecto laboriosam, necessitatibus
voluptatibus cupiditate accusantium corrupti placeat mollitia omnis tenetur! Incidunt fugiat
possimus quod, quidem itaque ducimus, perspiciatis eligendi, commodi voluptate cupiditate nihil
corrupti soluta maxime.
</p>
</section>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h2>this is Fourth page</h2>
<p className='text-center'>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quos similique harum, officiis facere odit
adipisci maxime obcaecati placeat, quibusdam totam magni eaque? Dicta id commodi saepe dignissimos
quam unde eaque.
</p>
</section>
</div>
);
};
export default TestAnimation;
You should move the initiation of the intersection observer into a useEffect hook.
Here is an example of an Observer component I've used in the past:
export default function Observer({ children, sectionRef, callback }) {
function onObserver(entries) {
const entry = entries[0];
console.log(entry);
if (entry.isIntersecting) {
callback(sectionRef.current.id);
console.log("element in:", entry.target.id);
} else {
console.log("element left:", entry.target.id);
}
}
useEffect(() => {
const refCopy = sectionRef;
let options = {
root: null,
rootMargin: "0% 0% -5% 0%",
threshold: [0.5],
};
let observer = new IntersectionObserver(onObserver, options);
if (refCopy.current) {
observer.observe(refCopy.current);
}
return () => {
if (refCopy.current) {
observer.unobserve(refCopy.current);
}
};
}, [sectionRef]);
return <div id="observation">{children}</div>;
}
And here is how to use it:
export default function Education({ children, handleInView }) {
const sectionRef = useRef(null);
return (
<Observer sectionRef={sectionRef} callback={handleInView}>
<section
ref={sectionRef}
id="education"
className="education"
data-scroll-section
data-scroll
data-scroll-class="purpleColor"
>
<Pencils />
<div className="details">
<div className="side-by-side">
<div className="title" data-scroll data-scroll-speed={2}>
<span>Fullstack</span>
<span> Software </span>
<span>Engineer</span>
</div>
</div>
</div>
</section>
</Observer>
);
}
tried posting to json db but only gets the Id in the json server with no postdate, posttitle, postdesc and image. i dont know i am doing wrong.
I would also like to like to update a post and then should be redirected to the homepage after updating the post.
I had tried using Redirect, useHistory and then useNavigate ffrom react-router-dom but still isnt working
import { useEffect, useState } from "react";
import "./write.css";
import { useNavigate } from "react-router-dom";
export default function Write() {
const [image, setImage] = useState();
const [posttitle, setPostTitle] = useState("");
const [postdesc, setPostDesc] = useState("");
const [postdate, setPostDate] = useState("20/30/2020");
// const [postDate, setPostDate] = useState("");
const navigate = useNavigate();
//==============================================================//
//Publishing or posting a post to the json server
const formSubmit = (e)=> {
e.preventDefault();
const docs = {
image,
posttitle,
postdate,
postdesc,
};
fetch("http://localhost:8005/posts", {
method: "POST",
headers: { contentType: "application/json" },
body: JSON.stringify(docs),
}).then(() => {
navigate.push("/home");
});
console.log(docs);
}
//===============================================================//
// const { id } = useParams(); not working
// getting the id of the post to be edited using window.location.href
const url = window.location.href;
const id = url.substring(url.lastIndexOf("=") + 1);
// //editing/Updating post data in the json-server file
// function editBtn() {
// fetch("http://localhost:8005/posts/" + id, {
// method: "PUT",
// body: JSON.stringify(),
// headers: {
// contentType: "application.json",
// },
// });
// }
return (
<div className="write">
<form className="writeform" onSubmit={formSubmit}>
<div>
<input />
date here
</div>
<div className="image_container">
{image && (
<div>
<img
className="writeimage"
alt="postimage"
src={URL.createObjectURL(image)}
onChange={(e) => {
setImage(e.target.src);
}}
/>
</div>
)}
</div>
<div className="writeformgroup">
<label htmlFor="fileinput">
<i className="writeicon fa-solid fa-plus"></i>
</label>
<input
id="fileinput"
type="file"
onChange={(e) => {
setImage(e.target.files[0]);
}}
style={{ display: "none" }}
/>
<input
type="text"
// value={postTitle}
className="writeinput"
onChange={(e) => {
setPostTitle(e.target.value);
}}
autoFocus
/>
</div>
<div className="writeformgroup">
<textarea
// value={postDesc}
onChange={(e) => {
setPostDesc(e.target.value);
}}
type="text"
className="writeinput writetext"
></textarea>
</div>
<button className="writesubmit">Publish</button>
</form>
<p>{posttitle}</p>
</div>
);
}
//JSON DB
{
"posts": [
{
"image": "https://images.pexels.com/photos/9968415/pexels-photo-9968415.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"posttitle": "Lorem ipsum dolor sit amet ",
"postdate": "20-29-2022",
"postdesc": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur sequi ad eveniet necessitatibus reiciendis dolor deleniti qui mod",
"id": 1
},
{
"image": "https://images.pexels.com/photos/13957041/pexels-photo-13957041.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"posttitle": "Lorem ipsum dolor sit amet ",
"postdate": "20-29-2022",
"postdesc": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur sequi ad eveniet necessitatibus reiciendis dolor deleniti qui mod",
"id": 2
},
{
"image": "https://images.pexels.com/photos/13715795/pexels-photo-13715795.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"posttitle": "Lorem ipsum dolor sit amet ",
"postdate": "20-29-2022",
"postdesc": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur sequi ad eveniet necessitatibus reiciendis dolor deleniti qui mod",
"id": 3
},
{
"image": "https://images.pexels.com/photos/13420447/pexels-photo-13420447.jpeg?auto=compress&cs=tinysrgb&w=400&lazy=load",
"posttitle": "Lorem ipsum dolor sit amet ",
"postdate": "20-29-2022",
"postdesc": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur sequi ad eveniet necessitatibus reiciendis dolor deleniti qui mod",
"id": 4
},
{
"image": "https://images.pexels.com/photos/13950829/pexels-photo-13950829.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"posttitle": "Lorem ipsum dolor sit amet ",
"postdate": "20-29-2022",
"postdesc": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur sequi ad eveniet necessitatibus reiciendis dolor deleniti qui mod",
"id": 5
},
{
"image": "https://images.pexels.com/photos/11055161/pexels-photo-11055161.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"posttitle": "Lorem ipsum dolor sit amet ",
"postdate": "20-29-2022",
"postdesc": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Saepe, suscipit inventore. Facilis ducimus quod ratione, fugiat temporibus, porro vitae consequuntur aspernatur sequi ad eveniet necessitatibus reiciendis dolor deleniti qui mod",
"id": 6
}
]
}
Try useHistory for redirect issues
import { useHistory } from 'react-router-dom';
const histroy = useHistory();
histroy.push({ pathname: '/home' });
Try async /await for fetch
const formSubmit = async () => {
try{
const response = await fetch("http://localhost:8005/posts", {
method: "POST",
headers: { contentType: "application/json" },
body: JSON.stringify(docs),
});
if(!response || !response.ok){
throw new Error('error message');
}
const data = response.json();
console.log(data);
}catch(error){
console.log(error);
}
}
help me please, I display the html markup of 6 posts, the first click works correctly, the second click I display the same posts. how should I add six new posts, and so every time I click?
I don't know what can be used instead of the slice method. demo https://jsfiddle.net/u9zc7p5v/13/
const content = mrd.map(function(data, elem) {
return `
<div class="blog__item">
<h2 class="blog__item-title">
${data.title}
</h2>
<input type="checkbox" class="read-more-state" id="post-${elem}" />
<p class="blog__item-text">
${data.body} <span class="blog__item-more">Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem itaque ducimus unde harum vitae quam provident. Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta sapiente odit laborum tempore sed quaerat a aliquam? Corrupti dolorum, tempora iste qui modi consectetur explicabo quia vel reiciendis nesciunt? Id!</span>
</p>
<label for="post-${elem}" class="blog__item-toggle" >Read More</label>
<div>${elem}</div>
</div>
`
}).slice(startNum, endNum).join('');
Increase the startNum value startNum+=6. then in slice function do startNum + endNum.
$(function(){
const blogs = document.querySelector('.blog__items')
const moreBtn = document.querySelector('.blog-btn')
let startNum = 0;
let endNum = 6;
async function getContent() {
let responce = await fetch('https://jsonplaceholder.typicode.com/posts');
let data = await responce.json();
return data;
}
$(moreBtn).on('click', async function(e) {
let mrd = await getContent();
console.log(mrd.length)
const content = mrd.map(function(data, elem) {
return `
<div class="blog__item">
<h2 class="blog__item-title">
${data.title}
</h2>
<p class="blog__item-text">
${data.body} <span class="blog__item-more">Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem itaque ducimus unde harum vitae quam provident. Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta sapiente odit laborum tempore sed quaerat a aliquam? Corrupti dolorum, tempora iste qui modi consectetur explicabo quia vel reiciendis nesciunt? Id!</span>
</p>
<label class="blog__item-toggle" >Read More</label>
<div>${elem}</div>
</div>
`
}).slice(startNum, startNum+endNum).join('');
console.log(startNum)
const el = $(content);
$(blogs).append(el)
el.on('click', function() {
});
startNum+= 6
});
});
I have used bootstrap plugin to collapse and expand the <div>s. I am able to do it for individual <div>'s but if i leave one <div> expanded and do a collapseAll(), the expanded <div> only getting collapsed. Please provide me a solution on this
html:
<body ng-controller="MainCtrl">
<div class="panel panel-default" ng-repeat="item in items">
<div class="panel-heading" ng-click="isCollapsed = !isCollapsed">{{item.title}}</div>
<div class="panel-body" collapse="isCollapsed">{{item.content}}</div>
</div>
<div>
<input type="checkbox" id="collapse_all_cards" ng-model="isCollapsed"><label for="collapse_all_cards">Collapse All</label>
</div>
</body>
js:
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.items = [{'title':'Item1','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu'},
{'title':'Item2','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu'},
{'title':'Item3','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu'}
]
});
link: http://plnkr.co/edit/mcnqeLJcTyaAuTI9JHb9
Please see this Plunk
Pretty sure this is the behavour you are after :)
The problem before was that the same "isCollapsed" property on scope was being used for the "collapse all" and the individual collapses so they were tripping each other up.
See the new controller code which has an individual boolean "isCollapsed" property for each item in the collection:
{'title':'Item1','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu', isCollapsed: true}
If you need any refinements to the code just ask :)
I started playing with AngularJS earlier today and I decided to build a simple app that consists of categories containing items.
The app has a sidebar where the categories are listed (aside.navigation) and a main view where all the items are listed. My plan was to load all the items ($scope.items) into an <ul> and filter them when a user clicks on one of the categories in the sidebar.
I tried a couple of things, including a simple filter withing the HTML, and a custom filter function. But I just can't get it to work. What would be the best way to do this?
This is my HTML
<html ng-app="stash">
...
<body ng-controller="StashCtrl">
<div id="stash">
<aside class="navigation">
<h1 class="logo"><strong>stash</strong>.io</h1>
<ul>
<li class="icon-latest active">Latest</li>
<li class="icon-star">Favorites</li>
</ul>
<ul>
<li ng-repeat="stash in stashes" class="icon-{{stash.icon}}">{{stash.title}}</li>
</ul>
</aside>
<section class="content">
<header>
<h1>Inbox <span class="item-count">{{totalItems}}</span></h1>
</header>
<ul class="items clearfix">
<li ng-repeat="item in items | filter:search">
<a ng-if="item.image != ''" href="#" class="has-image" ng-style="{'background-image': 'url({{item.image}})'}">
<h2>{{item.title}}</h2>
</a>
<a ng-if="item.excerpt != ''" href="#">
<h2>{{item.title}}</h2>
<p>{{item.excerpt}}</p>
</a>
<a ng-if="item.image == '' && item.excerpt == ''" href="#">
<h2>{{item.title}}</h2>
</a>
</li>
</ul>
</section>
</div>
</body>
...
</html>
And the JavaScript
var app = angular.module('stash', []);
app.controller('StashCtrl', function($scope) {
$scope.items = [
{id: '1', stash: '1', title: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit', excerpt: '', image: 'images/portfolio1.jpg'},
{id: '2', stash: '1', title: 'Lorem ipsum', excerpt: '', image: 'images/portfolio4.jpg'},
{id: '3', stash: '1', title: 'Lorem ipsum dolor sit amet', excerpt: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore, autem, repellat, asperiores, voluptates doloremque eaque suscipit beatae quisquam sint consequuntur illo minus ipsum optio officia alias ex veritatis libero veniam tempora fugit laborum facere vitae doloribus omnis aspernatur corporis rerum ad repudiandae accusamus placeat. Officia, aliquam, laborum sequi minima saepe et voluptatem! Consequuntur maiores veniam laboriosam quaerat quae delectus doloremque rem cumque aspernatur! Tenetur, beatae facere incidunt quae numquam vitae exercitationem quia saepe earum officiis porro asperiores id explicabo sapiente molestiae culpa atque facilis ipsa eligendi nobis quas eaque possimus temporibus nam mollitia distinctio dicta dolores. Expedita, quas aliquid modi!', image: ''},
{id: '4', stash: '2', title: 'Lorem ipsum', excerpt: '', image: 'images/portfolio2.jpg'},
{id: '5', stash: '', title: '5', excerpt: '', image: ''}
];
$scope.totalItems = $scope.items.length;
$scope.stashes = [
{id: '1', title: 'Ideas', icon: 'lightbulb'},
{id: '2', title: 'Onefinity Studios', icon: 'company'},
{id: '3', title: 'OnefinityCMS', icon: 'star'}
];
});
The easiest solution would be to set search to an object:
$scope.search = {};
And change the stash id on click in your stash list:
<a href ng-click="search.stash = stash.id">{{stash.title}}</a>
Here is a working demo.
If you want an active state just use ng-class and place it on your li:
<li ng-repeat="stash in stashes" ng-class="{'active': stash.id == search.stash}">...</li>
The filter is filtering by a property called search but it doesn't exist.
One way to do this is to save the selected stash into a currentStash property on the scope, then filter by it...
<li ng-repeat="stash in stashes" class="icon-{{stash.icon}}">
{{stash.title}}
</li>
And then change the filter to...
<li ng-repeat="item in items | filter : { stash: currentStash.id }">
JsBin