How to set iron-image src to use data-binding - javascript

I have an iron-image with a placeholder, and I'd like it to show an image when I press a button. But when I update the myImages prop, the image src doesn't update. Oddly enough the placeholder prop loadingImg works, I can update it and the placeholder changes.
For example, the HTML:
<iron-image preload fade
src$="{{myImages.test1}}"
placeholder$="[[loadingImg]]"></iron-image>
and the element prop:
myImages: {
type: Object,
value: {},
},
loadingImg: {
type: String,
value: "../../img/loading.jpg"
}
and the button just sets
myImages."test1 = "http://example.com/img1.jpg"}
Initially, src should point to undefined, as myImages is empty, so myImages.test1 should be undefined. But once I give myImages.test1 a url, the img src should update. What's going wrong here?

Changes to object properties aren't observable by default. In order to make this work, you need to use this.notifyPath()
This is why the prop loadingImg, which is just a string was causing the page to update on change, but the subproperty myImages.test1 was not.
Fixed sample code:
updateImage: function(imgSrc) {
this.myImages.test1 = imgSrc;
this.notifyPath('myImages.test1');
}

Related

TypeScript / Styled component passing image as props

I have the following code below which is meant to show the
"NoBillsLaptopPNG.src" on the screen, but no image is being rendered.
The images are being imported fine, but not sure why the image is not being displayed.
import NoBillsMobilePNG from "../../public/assets/quotes/no-bills-mobile.png"
import NoBillsLaptopPNG from "../../public/assets/quotes/no-bills-laptop.png"
export const NoBillsSummary = () => {
return <div>
<TestImg
NoBillsMobilePNG={NoBillsMobilePNG.src}
NoBillsLaptopPNG={NoBillsLaptopPNG.src}
></TestImg>
</div>;
};
const TestImg = styled.img<{
NoBillsMobilePNG: string;
NoBillsLaptopPNG: string;
}>`
// the reason the img is being passed in as props as media query will later be added to switch between images
src: url(${(NoBillsLaptopPNG) => NoBillsLaptopPNG.src});
width : 126.07px;
height : 107.59px;
margin-top: 2px;
`;
when you use the TestImg component, you are passing src as props to NoBillsLaptopPNG.
It would be better to name props as NoBillsLaptopPngSrc.
When you style TestImg, the NoBillsLaptopPNG input parameter is already src. Therefore, it makes no sense to refer to its src field again.
try this
src: url(${(NoBillsLaptopPNG) => NoBillsLaptopPNG});
With styled-components, when you interpolate a function within your style, styled-components will call that function with the entire props of the component.
Therefore, you have to either refer to a specific member, or destructure it, like for a usual React Function Component.
Next, it is normally not possible to change the src attribute of an <img> through style only (CSS). However, it is still possible to change its content.
Finally, as implied by #forlift's answer, you already pass just the .src value to the prop, so there is no need to re-access it again.
const TestImg = styled.img<{
NoBillsMobilePNG: string;
NoBillsLaptopPNG: string;
}>`
// Notice the destructuring of the props
content: url(${({ NoBillsLaptopPNG }) => NoBillsLaptopPNG});
width : "226.07px";
height : "207.59px";
margin-top: "2px";
`;

Image doesnt change although the src content changes

<img [(src)]="user.photo_url" alt="profileImage">
so i have the src coming from user object and i am changing the image and the user model is updated , but the url remains the same, although the content changes.
my Update function
this.appService.uploadProfileImage(this.user._id, this.imageFormData).then((response: any) => {
this.user = response;
});
so
the user.photo_url="somr-url" remains the same , but the image on the path changes.
But its not reflecting on the UI.
So how to reflect the changes on the img when the src is updated.
Things i tried but didnt worked.
Two way binding(as shown)
ChangeDetectorRef ( detectChange function)
try this
<img src="{{user.photo_url}}" alt="profileImage">
I just tested your code, you need to use [src] instead of [(src)].
I made a small demo in stackblitz & it works just fine!
<button (click)="changeImg()">change image source</button>
<br>
<img [src]="img" alt="profileImage">
ts code:
state : boolean;
img: string;
changeImg() {
this.state = ! this.state;
this.img = this.state ? "https://image.freepik.com/free-photo/blue-sky-with-clouds_1232-936.jpg" : "https://blogs.qub.ac.uk/queensuniversitybelfast/files/2015/05/red-sky.jpg"
}

Pass params to the loadData() to override the emptyText prop in viewCconfig method-EXTJS

I want to load the store with no records unless I check for certain condition. However I want to pass params to my loadData() in such a way that I can override the emptyText property with some other text.
this.superclass.constructor.call(this, Ext.apply({
viewConfig:{
emptyText: "No Records"
},
fields: [],
});
this.on('afterrender', function(){
new Ext.util.DelayedTask(function() {
this.getStore().loadData([]); //loading empty data
}, this).delay(300);
}, this);
So when I load the store I want to replace the emptyText: "Select actions" and once action selected it will display records or no records depending on the data.
If I insert the "Selection actions' text above in the viewConfig, it works ok on page load, but when no records found, it still displays the "Select actions".Is there any way I pass params to the loadData() function to override the text?
Thanks!
While #Saloo's example works, let me show you what object orientation can do for you.
If you don't want to copy the code over and over, behind every loadData, you can, in your store definition, override the existing loadData function to add another parameter, for example:
loadData:function(data, append, emptyText) {
if(emptyText) {
grid.emptyText = '<b> ' + emptyText + ' </b>';
grid.getView().refresh();
}
this.callParent(arguments);
}
and there you go.
loadData() method doesn't take any parameter.
loadData( data, [append] )
You have to handle any other event like select of combo and then change the viewConfig emptyText manually based on your condition and then refresh the view.
I have done this on grid component like this:
if (Ext.isEmpty(records)) {
grid.emptyText = '<b> No Document Found </b>';
grid.getView().refresh();
}

Update value of input type time (rerender) and focus on element again with React

In the spec for my app it says (developerified translation): When tabbing to a time element, it should update with the current time before you can change it.
So I have:
<input type="time" ref="myTimeEl" onFocus={this.handleTimeFocus.bind(null, 'myTimeEl')} name="myTimeEl" value={this.model.myTimeEl} id="myTimeEl" onChange={this.changes} />
Also relevant
changes(evt) {
let ch = {};
ch[evt.target.name] = evt.target.value;
this.model.set(ch);
},
handleTimeFocus(elName, event)
{
if (this.model[elName].length === 0) {
let set = {};
set[elName] = moment().format('HH:mm');
this.model.set(set);
}
},
The component will update when the model changes. This works well, except that the input loses focus when tabbing to it (because it gets rerendered).
Please note, if I would use an input type="text" this works out of the box. However I MUST use type="time".
So far I have tried a number of tricks trying to focus back on the element after the re-render but nothing seems to work.
I'm on react 0.14.6
Please help.
For this to work, you would need to:
Add a focusedElement parameter to the components state
In getInitialState(): set this parameter to null
In handleTimeFocus(): set focusElement to 'timeElem` or similar
Add a componentDidUpdate() lifecycle method, where you check if state has focusedElement set, and if so, focus the element - by applying a standard javascript focus() command.
That way, whenever your component updates (this is not needed in initial render), react checks if the element needs focus (by checking state), and if so, gives the element focus.
A solution for savages, but I would rather not
handleTimeFocus(elName, event)
{
if (this.model[elName].length === 0) {
let set = {};
set[elName] = moment().format('HH:mm');
this.model.set(set);
this.forceUpdate(function(){
event.target.select();
});
}
},
try using autoFocus attrribute.
follow the first 3 steps mention by wintvelt.
then in render function check if the element was focused, based on that set the autoFocus attribute to true or false.
example:
render(){
var isTimeFocused = this.state.focusedElement === 'timeElem' ? true : false;
return(
<input type="time" ref="myTimeEl" onFocus={this.handleTimeFocus.bind(null, 'myTimeEl')} name="myTimeEl" value={this.model.myTimeEl} id="myTimeEl" onChange={this.changes} autoFocus={isTimeFocused} />
);
}

Get React.refs DOM node width after render and trigger a re-render only if width has value has changed

I'm attempting to get the width of a ref DOM element and set state to then use within the Component render. The problem comes because this width changes on user input and when I try setState within componentDidUpdate it starts an infinite loop and my browsers bombs.
I created a fiddle here http://jsbin.com/dizomohaso/1/edit?js,output (open the console for some information)
My thinking was;
Component Mounts, setState: refs.element.clientWidth
User inputs data, triggers render
shouldComponentUpdate returns true only if new.state is not equal to old.state. My problem is, I'm not sure where makes sense to update this state?
Any help will be much appreciated, thanks for reading!
Brad.
var component = React.createClass({
componentDidMount: function() {
//Get initial width. Obviously, this will trigger a render,
//but nothing will change, look wise.
//But, if this is against personal taste then store this property
//in a different way
//But it'll complicate your determineWidth logic a bit.
this.setState({
elWidth: ReactDOM.findDOMNode(this.refs.the_input).getBoundingClientRect().width
})
},
determineWidth: function() {
var elWidth = ReactDOM.findDOMNode(this.refs.the_input).getBoundingClientRect().width
if (this.state.elWidth && this.state.elWidth !== elWidth) {
this.setState({
elWidth: elWidth
})
}
},
render: function() {
var styleProp = {}
if (this.state.elWidth) {
styleProp.style = { width: this.state.elWidth };
}
return (
<input ref="the_input" onChange={this.determineWidth} {...styleProp} />
)
}
})
I like to use .getBoundingClientRect().width because depending on your browser, the element might have a fractional width, and that width will return without any rounding.

Categories