From 3faa4ce6041ccb1aeaef3650d30fb61ed7f2116b Mon Sep 17 00:00:00 2001 From: Eitan Peer Date: Tue, 8 Aug 2017 11:28:43 +0300 Subject: [PATCH] Fix handling of dynamic updates to public-id. Fixes #83 Implement OnChanges for image and video components to support data binding of "public-id" attrbiute. Update photo_album sample with usage example. --- .../js/photo-list/photo-list.component.html | 29 +++++----- .../app/js/photo-list/photo-list.component.ts | 5 ++ src/cloudinary-image.component.spec.ts | 35 ++++++++++++ src/cloudinary-image.component.ts | 12 ++++- src/cloudinary-video.component.spec.ts | 53 +++++++++++++++++++ src/cloudinary-video.component.ts | 12 ++++- 6 files changed, 130 insertions(+), 16 deletions(-) diff --git a/samples/photo_album/app/js/photo-list/photo-list.component.html b/samples/photo_album/app/js/photo-list/photo-list.component.html index 3a26a5cd..26f2c2fd 100644 --- a/samples/photo_album/app/js/photo-list/photo-list.component.html +++ b/samples/photo_album/app/js/photo-list/photo-list.component.html @@ -2,19 +2,20 @@
- - - - - + + + + + +

Welcome!

@@ -221,4 +222,4 @@

{{photo.context.custom.photo}}

supported transformations. - \ No newline at end of file + diff --git a/samples/photo_album/app/js/photo-list/photo-list.component.ts b/samples/photo_album/app/js/photo-list/photo-list.component.ts index 8286a797..eb7c5ef0 100644 --- a/samples/photo_album/app/js/photo-list/photo-list.component.ts +++ b/samples/photo_album/app/js/photo-list/photo-list.component.ts @@ -11,6 +11,7 @@ import {Photo} from '../model/photo'; export class PhotoListComponent implements OnInit { private photos: Observable; + private publicId: string = 'officialchucknorrispage'; constructor( private photoAlbum: PhotoAlbum @@ -19,4 +20,8 @@ export class PhotoListComponent implements OnInit { ngOnInit(): void { this.photos = this.photoAlbum.getPhotos(); } + + changePublicId() { + this.publicId = (this.publicId === 'officialchucknorrispage') ? 'billclinton' : 'officialchucknorrispage'; + } } diff --git a/src/cloudinary-image.component.spec.ts b/src/cloudinary-image.component.spec.ts index 9bdd2f1d..f7780d49 100644 --- a/src/cloudinary-image.component.spec.ts +++ b/src/cloudinary-image.component.spec.ts @@ -183,5 +183,40 @@ describe('CloudinaryImage', () => { expect(img.attributes.getNamedItem('data-src')).toBeNull(); }); }); + + describe('Bound public-id', () => { + @Component({ + template: `` + }) + class TestComponent { + publicId: string = 'sample'; + } + + let fixture: ComponentFixture; + let des: DebugElement; // the elements w/ the directive + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + declarations: [CloudinaryTransformationDirective, CloudinaryImage, TestComponent], + providers: [{ provide: Cloudinary, useValue: localCloudinary }] + }).createComponent(TestComponent); + + fixture.detectChanges(); // initial binding + // all elements with an attached CloudinaryImage + des = fixture.debugElement.query(By.directive(CloudinaryImage)); + }); + + it('creates an img element with a bound public-id', () => { + const img = des.children[0].nativeElement as HTMLImageElement; + expect(img.src).toEqual(jasmine.stringMatching(/image\/upload\/sample/)); + + // Update data-bound publicId + fixture.componentInstance.publicId = 'updatedId'; + fixture.detectChanges(); + + // Verify that the img src has updated + expect(img.src).toEqual(jasmine.stringMatching(/image\/upload\/updatedId/)); + }); + }); }); diff --git a/src/cloudinary-image.component.ts b/src/cloudinary-image.component.ts index d701ba3d..4b230cb8 100644 --- a/src/cloudinary-image.component.ts +++ b/src/cloudinary-image.component.ts @@ -6,6 +6,8 @@ import { QueryList, AfterViewInit, OnInit, + OnChanges, + SimpleChanges, OnDestroy } from '@angular/core'; import {Cloudinary} from './cloudinary.service'; @@ -15,7 +17,7 @@ import {CloudinaryTransformationDirective} from './cloudinary-transformation.dir selector: 'cl-image', template: '' }) -export class CloudinaryImage implements AfterViewInit, OnInit, OnDestroy { +export class CloudinaryImage implements AfterViewInit, OnInit, OnChanges, OnDestroy { @Input('public-id') publicId: string; @@ -39,6 +41,14 @@ export class CloudinaryImage implements AfterViewInit, OnInit, OnDestroy { this.observer.observe(this.el.nativeElement, config); } + ngOnChanges(changes: SimpleChanges) { + // Listen to changes on the data-bound property 'publicId'. + // Update component unless this is the first value assigned. + if (changes.publicId && !changes.publicId.isFirstChange()) { + this.loadImage(); + } + } + ngOnDestroy(): void { this.observer.disconnect(); } diff --git a/src/cloudinary-video.component.spec.ts b/src/cloudinary-video.component.spec.ts index 4358c48e..5f413446 100644 --- a/src/cloudinary-video.component.spec.ts +++ b/src/cloudinary-video.component.spec.ts @@ -225,5 +225,58 @@ describe('CloudinaryVideo', () => { } }); }); + + describe('Bound public-id', () => { + @Component({ + template: ` + + + + ` + }) + class TestComponent { + publicId: string = 'watchme'; + } + + let fixture: ComponentFixture; + let des: DebugElement; // the elements w/ the directive + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + declarations: [CloudinaryTransformationDirective, CloudinaryVideo, TestComponent], + providers: [{ provide: Cloudinary, useValue: localCloudinary }] + }).createComponent(TestComponent); + + fixture.detectChanges(); // initial binding + + // Our element under test, which is attached to CloudinaryVideo + des = fixture.debugElement.query(By.directive(CloudinaryVideo)); + }); + + it('creates a video element with a bound public-id', () => { + const video = des.children[0].nativeElement as HTMLVideoElement; + // Created