Has anyone used foundation's slider component with React? I'm trying to capture and set the state based off the slider value, but I'm having serious issues. I'm looking for an approach that does not utilize jQuery.
When the input type is set to 'hidden' I can't seem to grab any data from the slider. When I change that to 'number', then an input box appears and I am able to grab data from that. The final design does not include an input box, so I need to maintain the 'hidden' attribute.
Can anyone seem to see a flaw in my code? At best, I get 'undefined' when trying to setState, but again, that's when I am showing an input box.
This is the code I have so far...
export class _DailyCheck extends Component {
state = {
levels: {
sleep: 0,
energy: 0,
stress: 0
},
show: true
}
_renderDaily () {
const { levels: { sleep, energy, stress } } = this.state
return (
<div>
<div className='content'>
<p className='headline-1 text-left'>
How is your day
going so far?
</p>
<div className='grid-x grid-padding-x'>
<fieldset className='small-12 large-12 cell'>
<label className='bold-body'>
Sleep Quality
<div
className='slider slider-margin'
data-slider
data-initial-start='3'
data-end='6'
>
<span
className='slider-handle'
data-slider-handle
tabIndex='1'
aria-controls='sleep'
>
</span>
<span
className='slider-fill'
data-slider-fill
>
</span>
<input
type='range'
id='sleep'
value={sleep}
onClick={(e) => this._handleDailyChange(e) }
/>
</div>
</label>
</fieldset>
</div>
</div>
</div>
)
}
_handleDailyChange (event) {
const levels = { ...this.state.levels }
levels[event.target.name] = levels[event.target.value]
this.setState({ levels })
}
Related
I am making a simple react app where there are two different div's..
One with select input and selected list,
<div id="container">
<div className="_2iA8p44d0WZ">
<span className="chip _7ahQImy">Item One</span>
<span className="chip _7ahQImy">Item Two</span>
<span className="chip _7ahQImy">Item Three</span>
<span className="chip _7ahQImy">Item Four</span>
<span className="chip _7ahQImy">Item Five</span>
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
Another will list down the selected option as fieldset,
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollDiv}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
Based on this solution, I have added createRef to the selected element like,
<div key={i} className="selected-element" ref={scrollDiv}>
</div>
Then I took Javascript query methods to get DOM elements like,
const chipsArray = document.querySelectorAll("#container > div > .chip");
Added click event listener to all the elements like,
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler);
});
Then scrollSmoothHandler like,
const scrollDiv = createRef();
const scrollSmoothHandler = () => {
console.log(scrollDiv.current);
if (scrollDiv.current) {
scrollDiv.current.scrollIntoView({ behavior: "smooth" });
}
};
But this doesn't work the way as expected.
Requirement:
On click over any item in first div, then its related fieldset needs to get smooth scrolled in another div..
Eg:
If user click on the element Item Four under
<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>
then the related fieldset needs to get scrolled into. Here the fieldset with legend as Item Four ..
I think also making the js dom query methods on react and it seems not a react way of implementation. Can anyone please kindly help me to achieve the result of scrolling to a related fieldset on click over the selected item..
Issue
React.createRef is really only valid in class-based components. If used in a functional component body then the ref would be recreated each render cycle.
Don't use a DOM query selector to attach onClick listeners to DOM elements. These live outside react and you'd need to remember to clean them up (i.e. remove them) so you don't have a memory leak. Use React's onClick prop.
When the selectedElements are mapped you attach the same ref to each element, so the last one set is the one your UI gets.
Solution
Use React.useRef in the functional component body to store an array of react refs to attach to each element you want to scroll into view.
Attach the scrollSmoothHandler directly to each span's onClick prop.
Attach each ref from the ref array created in 1. to each mapped field set you want to scroll to.
Code
import React, { createRef, useRef } from "react";
import { render } from "react-dom";
const App = () => {
const selectedElements = [
"Item One",
"Item Two",
"Item Three",
"Item Four",
"Item Five"
];
// React ref to store array of refs
const scrollRefs = useRef([]);
// Populate scrollable refs, only create them once
// if the selectedElements array length is expected to change there is a workaround
scrollRefs.current = [...Array(selectedElements.length).keys()].map(
(_, i) => scrollRefs.current[i] ?? createRef()
);
// Curried handler to take index and return click handler
const scrollSmoothHandler = (index) => () => {
scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
};
return (
<div>
<div id="container">
<div className="_2iA8p44d0WZ">
{selectedElements.map((el, i) => (
<span
className="chip _7ahQImy"
onClick={scrollSmoothHandler(i)} // <-- pass index to curried handler
>
{el}
</span>
))}
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
<div>
{selectedElements.map((item, i) => (
<div
key={i}
className="selected-element"
ref={scrollRefs.current[i]} // <-- pass scroll ref # index i
>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
</div>
);
};
Solution #2
Since you can't update any elements in the div with id="container" and all the onClick handlers need to be attached via querying the DOM, you can still use a curried scrollSmoothHandler callback and enclose an index in scope. You'll need an useEffect hook to query the DOM after the initial render so the spans have been mounted, and an useState hook to store a "loaded" state. The state is necessary to trigger a rerender and re-enclose over the scrollRefs in the scrollSmoothHandler callback.
const App = () => {
const selectedElements = [
"Item One",
"Item Two",
"Item Three",
"Item Four",
"Item Five"
];
const [loaded, setLoaded] = useState(false);
const scrollRefs = useRef([]);
const scrollSmoothHandler = (index) => () => {
scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
};
useEffect(() => {
const chipsArray = document.querySelectorAll("#container > div > .chip");
if (!loaded) {
scrollRefs.current = [...Array(chipsArray.length).keys()].map(
(_, i) => scrollRefs.current[i] ?? createRef()
);
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler(index));
});
setLoaded(true);
}
}, [loaded]);
return (
<div>
<div id="container">
<div className="_2iA8p44d0WZ">
<span className="chip _7ahQImy">Item One</span>
<span className="chip _7ahQImy">Item Two</span>
<span className="chip _7ahQImy">Item Three</span>
<span className="chip _7ahQImy">Item Four</span>
<span className="chip _7ahQImy">Item Five</span>
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollRefs.current[i]}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
</div>
);
};
I am learning to deal with VueJS and made a simple todo app. It works well, but I want to store data locally and make it persistent even if there is a page reload.
This is the code produced following instruction of a few useful tutorials (leaving CSS outside to ease readability):
<template>
<div class="main-container">
<div class="header md-elevation-4">
<h1 class="md-title">{{ header }}</h1>
</div>
<div class="todo-list">
<div class="row"></div>
<div class="row">
<!-- add new todo with enter key -->
<md-field class="todo-input">
<md-input
v-model="currentTodo"
#keydown.enter="addTodo()"
placeholder="Add a todo! It's easy!"
/>
</md-field>
<!-- for all todos, set class of edited todos -->
<ul class="todos">
<div class="list-div">
<li v-for="todo in todos" :key="todo.id">
<!-- binds checkbox to todo model after each instance; -->
<input
class="toggle-todo"
type="checkbox"
v-model="todo.completed"
/>
<!-- starts editing process on double click -->
<span
class="todo-item-label"
:class="{ completed: todo.completed }"
#dblclick="editTodo(todo)"
v-if="!todo.edit"
>{{ todo.label }}</span
>
<!-- concludes editing with enter click -->
<input
v-else
class="todo-item-edit"
type="text"
v-model="todo.label"
#keyup.enter="completedEdit(todo)"
/>
<!-- deletes todos using removeTodo method -->
<i
class="material-icons"
alt="remove toDo"
#click="removeTodo(todo)"
>delete</i
>
</li>
</div>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name: "RegularToolbar",
data() {
return {
header: "A VueJS ToDo App",
todos: [],
currentTodo: "",
completed: false, // add a completed property
editedToDo: null // add a edited property
};
},
methods: {
addTodo() {
this.todos.push({
id: this.todos.length,
label: this.currentTodo,
completed: false, // initializes property
edit: false // initializes property
});
this.currentTodo = "";
},
mounted() {
// console.log('App mounted!');
if (localStorage.getItem("todos"))
this.todos = JSON.parse(localStorage.getItem("todos"));
},
watch: {
todos: {
handler() {
// console.log('Todos changed!');
localStorage.setItem("todos", JSON.stringify(this.todos));
},
deep: true
}
},
removeTodo(todo) {
// allows users to remove todos
var index = this.todos.indexOf(todo);
this.todos.splice(index, 1);
},
editTodo(todo) {
todo.edit = true;
},
completedEdit(todo) {
todo.edit = false;
}
}
};
</script>
<style lang="scss" scoped></style>
As it is, all the JS part referring to mount and watch does not work. I am able to add new todos and delete them as I wish, but it does not retain the data if the user reloads the page.
Could some of the colleagues spot what I am missing here?
It's a problem of code organization:
Your mounted and watch sections are currently inside the methods section, which will prevent them from firing as expected.
Move those out into their own sections (both should be at the same level as methods) and you should be all set.
With those edits and nothing else, I've got your code working in a fiddle here: https://jsfiddle.net/ebbishop/dc82unyb/
Newbie dev learning React.
I'm trying to create an upvote functionality to a blog post in React but when I click on the upvote button I'm upvoting all of the blog post cards at once instead of the individual card.
How can I fix this? I believe the issue may be in the way I'm setting setState? But I may be wrong and looking for help.
Thanks in advance!
====
class Posts extends Component {
state= {
points: 0
}
componentDidMount() {
this.props.fetchPosts()
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.newPost) {
this.props.posts.unshift(nextProps.newPost);
}
}
handleClick = () => {
this.setState({points: this.state.points + 1})
}
render() {
const postItems = this.props.posts.map((post, index) => (
<div key={index} className="ui three stackable cards">
<div className="ui card">
<div className="content">
<div className="header">{post.title}</div>
<div className="meta"> {post.author}</div>
<div className="description">
<p>{post.body}</p>
</div>
</div>
<div className="extra content">
<i className="check icon"></i>
{this.state.points} Votes
</div>
<button className="ui button"
type="submit"
onClick={this.handleClick}>Add Point</button>
</div>
</div>
))
return (
<div>
<br />
<h2 className="ui header">
<i className="pencil alternate icon"></i>
<div className="content">
Blog Feed
<div className="sub header">Create New Post!</div>
</div>
</h2>
{postItems}
</div>
)
}
}
You have a single component storing the "points" state for all your posts. To achieve the functionality you described, each post should be it's own component with it's own state.
class Post extends Component {
state = {
points: 0
}
handleClick = () => {
this.setState({points: this.state.points + 1})
}
render = () =>
<div key={index} className="ui three stackable cards">
<div className="ui card">
<div className="content">
<div className="header">{this.props.title}</div>
<div className="meta"> {this.props.author}</div>
<div className="description">
<p>{this.props.body}</p>
</div>
</div>
<div className="extra content">
<i className="check icon"></i>
{this.state.points} Votes
</div>
<button className="ui button"
type="submit"
onClick={this.handleClick}>Add Point</button>
</div>
</div>
}
}
You are upvoting every card because you have only one counter. A separate counter should be defined for every card.
state = {}; // dictionary-a-like state structure
handleClick = (id) => () => {
this.setState((prevState) => ({
[id]: prevState[id] ? prevState[id] + 1 : 1, // check and increment counter
}));
}
onClick={this.handleClick(post.id)} // call function with post.id as argument
{this.state[post.id] || 0} Votes // display votes for every card
Note: I assumed that every card has it's own unique id, if not - index may come handy too.
You will need one counter for each post. Currently you only have a single counter for all posts, which means that they all display that same value.
The best way to achieve this would probably be to separate your post into its own component, and have that keep track of the counter.
The following solution uses a post ID (if you have it) to create a key in a stateful points object. Then, on click, you can add to the correct points key.
state = {
points: {}
}
handleClick = postId => {
this.setState({
points: {
...this.state.points,
[postId]: (this.state.points[postId] || 0) + 1
}
})
}
const postItems = this.props.posts.map((post, index) => (
...
<div className="extra content">
<i className="check icon"></i>
{this.state.points[post.id] || 0} Votes
</div>
<button
className="ui button"
type="submit"
onClick={() => this.handleClick(post.id)}
>
Add Point
</button>
...
)
I am having a weird issue with my single file Vue component where when I update an unrelated variable (Vue.js variable), all of my inputs (stuff I typed in, not the elements themselves.) disappear.
I have worked with Vue single file components for a few months now and I have never ran into something like this. Here is the weird part, the variable gets updated successfully as expected, but if I include the variable inside of the template at all that is when all the inputs disappear.
The function is looking up 'agents', then letting the user know how many records have been found and whether or not he/she would like to view them. If the user clicks on the "View" link, then they are shown a bootstrap-modal which shows them the records so that they could select one.
Here is what I have already tried:
Removing all ids from the inputs and using only refs="" to get the values.
changing the 'agents' variable name. Thought maybe it was conflicting with some rogue global or something.
Double checked that the parent component and this component was not being re-rendered. I did that by putting console.log() comments in the mounted() function and as expected it is only rendering once.
Watched the key using Vue dev tools extension to make sure the key was not being changed somehow.
Executed the searchAgent() function in a setTimeout(()=>{},5000) to see whether my use of _.debounce was causing issues.
Used jquery to fetch the values from the inputs instead of refs.
Assign the new records to a local variable agentsArray, then pass that into a function which assigns it to the vue variable 'agents' (its basically a needlessly longer route to the same thing but I thought WHY NOT TRY IT)
Double checked all my uses of 'this' to make sure that I was not accidentally using the wrong this and causing some unknown bug.
Using V-model, but using that doesn't help because I would still have to include the 'agents' inside of the modal in the template.
Using a v-if statement to render the modal HTML in the template only after 'agents' is not an empty array.
Update: Based on a suggestion, removed the function from inside of $(document).ready() inside of the mounted() function.
Template:
<template>
<div class="Q mb-0">
<i class="far fa-question-circle"></i>
<center>
<p class="display-1">{{title}}</p>
{{prefix}} is Representing Themselves Skip This Step.
<div id="searchResults" class="hidden" style="margin-top:5px;">
<a id="searchResultsText" class="SkipStepStyle"></a>
<a
id="viewSearchResults"
style="font-weight: bold;"
class="hidden SkipStepStyle"
v-on:click="displayAgents"
>
View
</a>
</div>
<form class="mt-2 BuyerSellerAgentInfo">
<div class="form-row">
<div class="form-group col-md-6">
<input
ref="NameFirst"
type="text"
:name="prefix+'sAgent_NameFirst'"
placeholder="FIRST NAME"
class="AnswerChoice"
:value="currentAnswers[prefix+'sAgent_NameFirst'].Answer"
>
</div>
<div class="form-group col-md-6">
<input
ref="NameLast"
type="text"
:name="prefix+'sAgent_NameLast'"
placeholder="LAST NAME"
class="AnswerChoice"
:value="currentAnswers[prefix+'sAgent_NameLast'].Answer"
>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<input
ref="Email"
type="text"
:name="prefix+'sAgent_Email'"
placeholder="EMAIL ADDRESS"
class="AnswerChoice"
:value="currentAnswers[prefix+'sAgent_Email'].Answer"
>
</div>
<div class="form-group col-md-6">
<input
ref="Phone"
type="text"
:name="prefix+'sAgent_Phone'"
maxlength="14"
placeholder="PHONE #"
class="AnswerChoice"
:value="currentAnswers[prefix+'sAgent_Phone'].Answer"
>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<input
ref="Brokerage"
type="text"
:name="prefix+'sAgent_Brokerage'"
placeholder="AGENT'S BROKERAGE"
class="AnswerChoice"
:value="currentAnswers[prefix+'sAgent_Brokerage'].Answer"
>
</div>
<div class="form-group col-md-6">
<input
ref="License"
type="text"
:name="prefix+'sAgent_License'"
placeholder="AGENT'S LICENSE #"
class="AnswerChoice"
:value="currentAnswers[prefix+'sAgent_License'].Answer"
>
</div>
</div>
<input
class="AnswerChoice"
type="hidden"
:name="prefix+'sAgent_ID'"
:value="currentAnswers[prefix+'sAgent_ID'].Answer || '1'"
>
<input
class="AnswerChoice"
type="hidden"
:name="prefix+'sAgent_BrokerageID'"
:value="currentAnswers[prefix+'sAgent_BrokerageID'].Answer || '1'"
>
</form>
</center>
<div v-if="agents.length > 0" class="modal" id="AgentPopup">
<div class="vertical-alignment-helper">
<div class="modal-dialog vertical-align-center">
<div class="modal-content">
<div class="modal-body">
<center>
<h5 class="d-inline-block mb-3">Select {{prefix}}'s Agent:</h5>
</center>
<button v-on:click="displayCategories" type="button" class="close shadow" data-dismiss="modal">×</button>
<ul>
<li v-for="agent in agents">{{ agent.NameFull || agent.NameFirst+' '+agent.NameLast }}</li>
<li class="border-0">{{prefix}}’s agent is not in this list</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
Script:
import _ from 'lodash';
export default {
name: "AgentInformation",
props: {
friendlyIndex: {
type: String,
default: null,
},
title: {
type: String,
default: null,
},
answerChoices:{
type: Array,
default: () => []
},
currentAnswers: {
type: Object,
default: () => {},
},
prefix: {
type: String,
default: '',
},
token: {
type: String,
default: '',
},
},
methods: {
debounceFunction(func,timer){
let vueObject = this;
return _.debounce(()=>{
vueObject[func]();
},timer);
},
displayCategories(){
$('.categories').show();
},
displayAgents(){
$('.categories').hide();
$('#AgentPopup').modal({backdrop:'static',keyboard:false});
},
searchAgent() {
let vueObject = this;
console.log('calling searchAgent()');
let agentSearchRoute = correctVuexRouteURL(vueObject.$store.getters.routeName('search.agent'));
if (!agentSearchRoute) genericError('Agent Search Route Not Found. Error code: a-s-001');
else
{
let dataObject = {
NameFirst: this.$refs.NameFirst.value,
NameLast: this.$refs.NameLast.value,
Email: this.$refs.Email.value,
Phone: this.$refs.Phone.value,
License: this.$refs.License.value,
_token: this.token,
};
console.log(dataObject);
vueObject.$http.post(agentSearchRoute, dataObject).then((r) => {
let status = r.body.status;
if (status == 'success')
{
vueObject.agents = r.body.agents;
let searchResultsContainer = $('#searchResults');
let searchResultsText = $('#searchResultsText');
let viewSearchResultsLink = $('#viewSearchResults');
let agentCount =
vueObject.agents.length;
searchResultsContainer.removeClass('hidden');
if(agentCount > 0)
{
let rText = agentCount > 1 ? 'records' :
'record';
searchResultsText.text(agentCount+' '+rText+'
found.');
viewSearchResultsLink.removeClass('hidden');
}
else
{
if (!viewSearchResultsLink.hasClass('hidden'))
viewSearchResultsLink.addClass('hidden');
searchResultsText.text('No records found.');
}
}
});
}
},
},
data(){
return {
agents: [],
}
},
mounted() {
let vueObject = this;
console.log('mounted');
$(document).ready(function(){
$('#phone').mask('(###)-###-####');
$('.AnswerChoice').on('input', () => {
let searchAgent =
vueObject.debounceFunction('searchAgent',500);
searchAgent();
});
});
}
}
It seems that the issue is the template does not like the 'agents' variable to be inside of it. When I remove the modal container or just the references to 'agents' it works as expected. If I change the variable name it does not solve the issue.
Any thoughts on the solution? Am I missing something blatantly obvious and stupid?!
Edit: Something I forgot to add, I don't think affects this in any way but it is worth mentioning. This component is rendered dynamically inside of the parent.
Rendering the component:
<component
v-for="(component,i) in selectedView"
:is="component['Component']"
v-bind="bindAttributes(component)"
:key="component.ID"
>
</component>
Changing agents will cause the whole template to be re-run. Not just the bits that mention agents, everything in that template will be updated.
When a user types into one of your <input> elements you aren't storing that value anywhere. You've got a :value to poke the value in but you aren't updating it when the value changes. The result will be that when Vue re-renders everything it will jump back to its original value.
You should be able to confirm this by setting the initial values within currentAnswers to be something other than empty. You should find that whenever agents changes it jumps back to those initial values.
The solution is just to ensure that your data is kept in sync with what the user types in. Typically this would be done using v-model but that's a bit tricky in this case because you're using a prop for the values and you shouldn't really be mutating a prop (one-way data flow). Instead you should use events to communicate the required changes up to whichever component owns that data.
Here is a simple test case to demonstrate the issue in isolation:
new Vue({
el: '#app',
data () {
return {
count: 0,
value: 'initial'
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<input :value="value">
<button #click="count++">Click count: {{ count }}</button>
</div>
I am trying to create 3 tooltips in a page, Its not working , only one tooltip should be open on click anyother tooltip should be closed.
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('TooltipDemoCtrl', function ($scope, $sce) {
$scope.tooltip = {
1: false,
2: false,
3: false
};
$scope.tooltipCloseActive = function(activeTooltip) {
console.log($scope.tooltip);
_.set($scope.tooltip, activeTooltip, true);
_.forOwn($scope.tooltip, function(value, key) {
console.log(value+'*************'+key);
if(activeTooltip !== key && value === true){
console.log('#'+key);
_.set($scope.tooltip, key, false);
$scope.triggerClickOnTooltip(key);
console.log(key);
}
});
};
$scope.triggerClickOnTooltip = function(id) {
setTimeout( function(){
angular.element(document.querySelectorAll('#'+id)).trigger('click');
}, 100);
};
});
HTML:
<div class="col-xs-10 col-sm-4">
<p id="1" tooltip-trigger="click"
uib-tooltip="I am a tooltip 1." ng-click="tooltipCloseActive('1');">
<span>tooltip 1:</span>
</p>
<br>
<p id="2" tooltip-trigger="click"
uib-tooltip="I am a tooltip 2." ng-click="tooltipCloseActive('2')">
<span >tooltip 2:</span>
</p>
<br>
<p id="3" tooltip-trigger="click"
uib-tooltip="I am a tooltip 3." ng-click="tooltipCloseActive('3')">
<span>tooltip 3:</span>
</p>
<br>
</div>
I have written code for multiple ui tooltips and want to close other tooltips when one of the tooltip is clicked.
It is going into infinite loop so when I am triggering click .
Just want to know how to make it work :
Possible Solution :
1) Differentiating the user click and trigger click :
I was not able to differentiate (I know how we can do in jquery but not in angular)
2) Use tooltip flags ( which I did it didn't work)
3) Upgrading ui bootstrap and use outsideClick (Which I cant afford doing in our application right now)
Is there any way I can solve this mystery of enable only one tooltip at a time.
Any help would be greatly appreciated.
PLUNKER : http://plnkr.co/edit/mjqGa26auDSY2G8ThAk4?p=preview
I think I was over thinking on trigger :
I have used is-open with wrong format due to which I was not able to get the
Working plunker using mutliple tooltips and enabling using tooltip-is-open http://plnkr.co/edit/gKqdoA3qK74XD1r9b5PR?p=info
HTML:
Tooltip Text
<br/> Toggle value: {{ tooltip.isTTOpen }}
</div>
<br/>
<br/>
<br/>
<br/>
<span tooltip-template="'myTooltipTemplate.html'" tooltip-trigger="none" tooltip-is-open="tooltip.isTTOpen2" tooltip-placement="top" ng-click="closeTooltip('isTTOpen2')">Tooltip Text</span>
<br/> Toggle value: {{ tooltip.isTTOpen2 }}
<br/>
<br/>
<br/>
<br/>
<span tooltip-template="'myTooltipTemplate.html'" tooltip-trigger="none" tooltip-is-open="tooltip.isTTOpen3" tooltip-placement="top" ng-click="closeTooltip('isTTOpen3')">Tooltip Text</span>
<br/> Toggle value: {{ tooltip.isTTOpen3 }}
JS:
$scope.tooltip = {
isTTOpen: false,
isTTOpen2: false,
isTTOpen3: false
};
$scope.closeTooltip = function(tooltip) {
console.log(tooltip);
for (var key in $scope.tooltip) {
if ($scope.tooltip.hasOwnProperty(key)) {
console.log(key + " -> " + $scope.tooltip[key]);
if (tooltip === key) {
$scope.tooltip[key] = true;
} else {
$scope.tooltip[key] = false;
}
}
}
};