is there a way to change a background-image on conditions?
Im trying to build a weatherapp and I will change the background of a div.
Like:
Weather api returns:
rainy -> change background image to rain.jpg
snow -> change background image to snow.jpg
sunny -> change background to sunny.jpg
etc.
I've tried multiple ways already but nothing worked.
<template>
<div :class="{background_image}"></div>
</template>
<script>
export default {
// ...
data() {
return {
backgroundImage: 'snow'
},
computed:{
background_image : function () {
switch(this.backgroundImage) {
case 'snow':
return 'bg-snow';
case 'rainy':
return 'bg-rainy';
case 'sunny':
return 'bg-sunny';
default:
return 'bg-default';
}
}
},
methods: {
apiCall() {
//api call update background image according to the response
this.backgroundImage = response ; // response contains sunny text
}
},
// ...
}
</script>
<style>
.bg-sunny{
background-image: url('sunny.jpg');
}
.bg-snow{
background-image: url('snow.jpg');
}
.bg-rainy{
background-image: url('rainy.jpg');
}
.bg-default{
background-image: url('default.jpg');
}
</style>
You can achieve this behavior by looking up the image in an object, where you have defined your key and the corresponding image value. In addition, you need to tell webpack to require that media file. That require tells webpack to treat this file as a request.
<template>
<div :style="{ backgroundImage: `url(${weatherTypes[getWeatherType()]})` }"></div>
</template>
<script>
export default {
// ...
data() {
return {
weatherTypes: {
snow: require('some/path/snow.png'),
sun: require('some/path/sun.png'),
// ...
}
}
},
methods: {
getWeatherType() { return 'snow'; },
},
// ...
}
</script>
Reproduction link
Related
I have a component that has a hover animation where 4 images are rotated in a loop:
animation: changeImg-1 2.5s linear infinite;
#keyframes changeImg-1 {
0%, 100% { background-image: url('images/wel1.png'); }
25% { background-image: url('images/wel2.png'); }
50% { background-image: url('images/wel3.png'); }
75% { background-image: url('images/wel4.png'); }
}
Now I want to make this component reusable by being able to pass image strings in as props, those get assigned as css variables which then get picked up by the animation.
I got as far as defining the css variable with a path in a computed property which is then used in the css:
computed: {
userStyle () {
return {
'--myBackground': `url(${require('#/components/ImagesInText/images/wel1.png')})`,
}
}
},
CSS:
.image {
background:var(--myBackground);
}
What I can't get to work is to pick up an image path from props and use it in the computed property...
props: {
image: { type: String, default: '#/components/ImagesInText/images/wel1.png' },
},
If I do this below I get en error: Cannot find module '#/components/ImagesInText/images/wel1.png'"
computed: {
userStyle () {
return {
'--myBackground': `url(${require( this.image )})`,
}
}
},
When using a variable path/filename, require needs some assistance. You must hard code at least the first portion of the path as a string.
For example, this works:
const filename = 'wel1.png';
require('#/components/ImagesInText/images/' + filename); // <-- The string is needed
This works too:
const path = 'components/ImagesInText/images/wel1.png';
require('#/' + path); // <-- This is good enough too
But this would not work:
const fullpath = '#/components/ImagesInText/images/wel1.png';
require(fullpath); // <-- No. Can't infer the path from a variable only
As the way mentioned In this thread. it's working perfectly for me.
<div class="register-img" :style="{'background-image': 'url(' + require('#/assets/images/register-image.png') + ')'}"></div>
I have an view in Polymer whereby users can scan a QR code and the data will appear as a heading below the video preview. This is the code.
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="shared-styles.html">
<script type="text/javascript" src="../js/instascan.min.js"></script>
<dom-module id="my-view1">
<template>
<style>
:host {
display: block;
text-align: center;
}
#preview {
width: 100% !important;
height: auto !important;
border-radius: 2px;
}
</style>
<!-- Video preview of camera for QR code scanning -->
<video id="preview"></video>
<!-- List of QR code items scanned-->
<h1>{{bucketItems}}</h1>
</template>
<script>
class MyView1 extends Polymer.Element {
static get is() { return 'my-view1'; }
static get properties() {
return {
bucketItems: {
type: String,
reflectToAttribute: true
},
}
}
// Once page has loaded
connectedCallback() {
super.connectedCallback();
// List of items in bucket (contains scanned ingredients)
var itemsBucket = [];
// Scan QR Code using Instascanner
let scanner = new Instascan.Scanner({ video: this.$.preview });
scanner.addListener('scan', function (content) {
// Access the QR code content using "content"
if (!itemsBucket.includes(content)) {
// Only add items once to the bucket
itemsBucket.push(content);
}
this.bucketItems = itemsBucket.toString();
console.log(this.bucketItems);
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
scanner.start(cameras[0]);
} else {
console.error('No cameras found.');
}
}).catch(function (e) {
console.error(e);
});
}
}
window.customElements.define(MyView1.is, MyView1);
</script>
</dom-module>
When I console.log(this.bucketItems) I can see the list of items they have scanned but the data is not visible in the h1 tag. How do I bind it correctly. I am new to polymer and just beginning to learn data bindings.
This problem is the context of your callback is not bound to the Polymer object, so it uses the outer context.
You could switch to arrow functions to automatically bind the Polymer object, use :
scanner.addListener('scan', content=> {
instead of:
scanner.addListener('scan', function (content) {
DEMO
I am trying to get my head around a scenario with CSS components:
I have a react component that uses its own classes. This component has a little helper subcomponent that also has its own classes. Now: When a specific state in the main component is set and a specific class is applied then the helper component's css should react on that class.
For instance:
Component A uses Component B to show something.
Component A gets clicked on and react sets a "clicked"-class on that component
Component B should then visually react on that class
In plain CSS (or similar) I would do this:
Component A:
.component {
height: 10px;
}
.component.clicked {
height: 5px;
}
Component B
.clicked {
.subComponent {
background-color: orange;
}
}
I know that there is a react way to do this. This kind of thing should be done with states and props which are being passed between the components so that this kind of situation gets avoided altogether. But I am currently refacturing a project that still has these issues and I don't really get how to do this properly with react-css-modules.
By the way: My current workaround uses :global but I'd really, really like to avoid this...
Component B:
.clicked:onclick, .subComponent {
// code ...
}
This should do it.
If not I'm just bad at css, or confused about your question.
Parent:
var ComponentA = React.createClass({
getInitialState: function() {
return {
isClicked: false
}
},
onClick: function() {
this.setState({ isClicked: !this.state.isClicked });
}),
render() {
return (
<div className={this.state.isClicked ? "component clicked" : "component"}>
<ComponentB isClicked={this.state.isClicked}/>
</div>
);
}
});
Child:
var ComponentB = React.createClass({
getDefaultProps: function() {
return {
isClicked: false
}
},
render() {
return (
<div className={this.props.isClicked ? "subComponent clicked" : "subComponent"}>
I am the subComponent
</div>
);
}
});
When running helper brings values are stored in the variable verCandidatos.postulados.
Once I get me the information I need to get a document that is linked (using the function ng-init="candidato = la postulado.candidato()) wich runs on the helper from file: collection.js.
Sometimes the html shows the properties: {{candidato.nombre}}, {{candidato.apellidos}} and {{candidato.sexo}} correctly, and sometimes appear empty, why?
Is very strange, like a bug or something. How is possible that behavior?
The information is being obtained, because the ng-repeat works and shows elements.
Below is the publishComposite(), collection.js, html and js client
html client
my-app/imports/ui/components/vacantes/verCandidatos/ verCandidatos.html
<div ng-repeat="postulado in verCandidatos.postulados">
<div ng-init="candidato = postulado.candidato();">
{{candidato.nombre}}
{{candidato.apellidos}}
{{candidato.sexo}}
</div>
</div>
js in client
my-app/imports/ui/components/vacantes/verCandidatos/ verCandidatos.js
imports ...
class VerCandidatos {
constructor($scope, $reactive, $stateParams) {
'ngInject';
$reactive(this).attach($scope);
this.vacanteId = $stateParams.vacanteId;
this.subscribe('vacantes.candidatosOseleccionados', ()=> [{vacanteId: this.vacanteId}, {estado: 1}]);
this.helpers({
postulados (){
return Postulaciones.find();
}
});
}
}
collection.js
my-app/imports/api/postulaciones/ collection.js
imports...
export const Postulaciones = new Mongo.Collection('postulaciones');
Postulaciones.deny({...});
Postulaciones.helpers({
candidato(){
return Candidatos.findOne({_id: this.candidatoId});
}
});
publish.js:
my-app/imports/api/vacantes/server/ publish.js
imports...
if (Meteor.isServer) {
Meteor.publishComposite('vacantes.candidatosOseleccionados', function (vacanteId, estado) {
const selector = {$and: [estado, vacanteId]};
return {
find: function () {
return Postulaciones.find(selector);
},
children: [
{
find: function (postulacion) {
return Candidatos.find({_id: postulacion.candidatoId}, {
fields: {
nombre: 1,
apellidos: 1,
sexo: 1,
}
});
}
}
]
};
});
}
Any ideas?
- Thanks,
The ISSUE was in html
The solution was deteted ng-init and call directly the helpers inside collection.js, the other files (js in client, collection.js, publish.js) aren't modify.
The html file is as follows:
<div ng-repeat="postulado in verCandidatos.postulados">
{{postulado.candidato().nombre}}
{{postulado.candidato().apellidos}}
{{postulado.candidato().sexo}}
</div>
Thanks for read.
And I hope you will be useful.
I'm using Ember.js with ember-cli and ember-data. Until now, development went quite smoothly but now I encountered an issue with css transitions which I can't solve myself.
I have a list. The list contains elements which have subelements. These subelements are also rendered as a list.
I fetch the data with ember-data from a REST API. After the data is received I want to fade in (css opacity) the list. But this does not work correctly. Sometime the transition is shown and sometimes not. I'm afraid it is a timing issue. So I added Ember.run.next to my code but it didn't help. When I add setTimeout with 1ms inside Ember.run.next it works like expected (at least on my computer). This feels quite weird. Here is my code I have so far. Every feedback appreciated.
controller.js:
export default Ember.Controller.extend({
//...
objects: []
//...
_pushToMatchings: function (response) {
var tempArray = [];
var pushed = false;
for (var i = 0, length = this.get('objects.length'); i < length; i++) {
pushed = false;
var match = this.get('objects').objectAt(i);
if (match.get('meta.items').objectAt(0) === response.get('meta.items').objectAt(0)) {
tempArray.pushObject(response);
pushed = true;
} else {
tempArray.pushObject(match);
}
}
if (!pushed) {
tempArray.pushObject(response);
}
this.set('objects', tempArray);
},
fetch: function() {
var self = this;
// find parent item
this.get('store').find('item', id).then(function (item) {
self._pushToMatchings(Ember.Object.create({
meta: {
items: [id],
isLoading: true,
label: item.get('label')
},
content: []
}));
self.set('isOpen', true);
// child object
self.get('store').find('child', searchParams).then(function (result) {
(function (resultPtr) {
Ember.run.next(function () {
setTimeout(function () { // #todo why do we need timeout here? whitout there is no fade out with opacity in css possible
resultPtr.set('meta.isLoaded', true);
}, 1); // 1 is enough but give spinner some time otherwise it looks ugly
});
}(result));
result.set('meta.label', item.get('label'));
self._pushToMatchings(result);
}, function (error) { /* ... */ });
}, function (error) { /* ... */ });
}
}
controller.hbs:
<div>
{{item-list close="close" elements=objects }}
</div>
item-list.js
export default Ember.Component.extend({
elements: [],
actions: {
close: function () {
this.sendAction('close');
}
}
});
item-list.hbs
<div class="items-list__buttons">
<i class="icon-close_32" {{action "close" }}></i>
</div>
<div class="items-list__content">
{{#each matching in elements}}
<div class="items-list__item">
<h2>{{t "items.offers" }} {{matching.meta.label}}</h2>
{{spinner-element hideEvent=matching.meta.isLoaded }}
<div {{bind-attr class=":items-list__box matching.meta.isLoaded:items--fadeIn" }}>
{{#each item in matching.content}}
<div>
<!-- Render details of item -->
</div>
{{/each}}
</div>
</div>
{{/each}}
</div>
CSS:
.items-list__box {
opacity: 0;
transition: opacity 150ms ease 100ms;
}
.items--fadeIn {
opacity: 1;
}
You can use Ember.run.later, works same way than setTimeout.
Ember.run.later(this ,function(){
resultPtr.set('meta.isLoaded', true);
}, 100);
I'm not sure but this is neccesary because the div would be render with the class "items--fadeIn" that the transition wouldn't occur. I've done this way and worked for me, just try incrementing the time a little.
I know this is a late answer, but for others receiving a similar issue:
Your problem is that Ember is re-rendering your entire list of items in your {{#each because every time something changes you are giving it an entirely new array of objects, instead of changing the properties of the objects in the array. What you need to do is to define your array of objects and manipulate their properties so that only the objects that change get re-rendered.