New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Live-bound dynamic attributes don't get updated properly if they don't exist on initial execution #157

Closed
guilambert opened this Issue Nov 16, 2012 · 13 comments

Comments

Projects
None yet
6 participants
@guilambert

This was discussed and fixed for EJS templates:

https://forum.javascriptmvc.com/topic/live-binding-an-image

But it doesn't work with Mustache templates. Check the following fiddle:

http://jsfiddle.net/donejs/4SmxJ/2/

It gives the !! error

@amcdnl

This comment has been minimized.

Show comment
Hide comment
@amcdnl

amcdnl Nov 16, 2012

Contributor

Does this happen in EJS too?

Contributor

amcdnl commented Nov 16, 2012

Does this happen in EJS too?

@daffl

This comment has been minimized.

Show comment
Hide comment
@daffl

daffl Nov 16, 2012

Contributor

Yes, but the solution for EJS looked like this:

<img <%= this.attr('image') ? "src='" + this.image + "'" : "" %> alt="An image" />

What I think should be the equivalent in Mustache doesn't work the same though:

<img {{#image}}src="{{image}}"{{/image}} alt="An image" />

Should we just add a special case for src attributes in the view renderer?

Contributor

daffl commented Nov 16, 2012

Yes, but the solution for EJS looked like this:

<img <%= this.attr('image') ? "src='" + this.image + "'" : "" %> alt="An image" />

What I think should be the equivalent in Mustache doesn't work the same though:

<img {{#image}}src="{{image}}"{{/image}} alt="An image" />

Should we just add a special case for src attributes in the view renderer?

@ghost ghost assigned andykant Nov 16, 2012

@andykant

This comment has been minimized.

Show comment
Hide comment
@andykant

andykant Nov 16, 2012

Contributor

I'll look into why this is happening, but in the meantime, here's a workaround:

<img {{#image}}src="{{.}}"{{/image}} alt="An image" />
Contributor

andykant commented Nov 16, 2012

I'll look into why this is happening, but in the meantime, here's a workaround:

<img {{#image}}src="{{.}}"{{/image}} alt="An image" />
@guilambert

This comment has been minimized.

Show comment
Hide comment
@guilambert

guilambert Nov 16, 2012

It does work with your workaround, thanks !

It does work with your workaround, thanks !

andykant added a commit that referenced this issue Jan 28, 2013

Added Mustache/EJS tests for Observe live binding issue #157
Observe properties added after initialization do not live update
properly in attributes
@andykant

This comment has been minimized.

Show comment
Hide comment
@andykant

andykant Jan 28, 2013

Contributor

This ended up not being an issue with images specifically. From what I've narrowed it down to, can/view/render fails to properly set up live binding for observe properties if it is being set to a node's attribute (in this case src) if the property doesn't exist when the template is originally rendered. This occurs with both Mustache and EJS, so I added tests for both in the live-bind-observe-attr-157 branch.

This works:

data = new can.Observe({
        user: 'Tina Fey',
        messages: 0,
        image: 'some-value'
    })
data.attr('image', 'http://farm8.staticflickr.com/7102/6999583228_99302b91ac_n.jpg');

This doesn't:

data = new can.Observe({
        user: 'Tina Fey',
        messages: 0
    })
data.attr('image', 'http://farm8.staticflickr.com/7102/6999583228_99302b91ac_n.jpg');
Contributor

andykant commented Jan 28, 2013

This ended up not being an issue with images specifically. From what I've narrowed it down to, can/view/render fails to properly set up live binding for observe properties if it is being set to a node's attribute (in this case src) if the property doesn't exist when the template is originally rendered. This occurs with both Mustache and EJS, so I added tests for both in the live-bind-observe-attr-157 branch.

This works:

data = new can.Observe({
        user: 'Tina Fey',
        messages: 0,
        image: 'some-value'
    })
data.attr('image', 'http://farm8.staticflickr.com/7102/6999583228_99302b91ac_n.jpg');

This doesn't:

data = new can.Observe({
        user: 'Tina Fey',
        messages: 0
    })
data.attr('image', 'http://farm8.staticflickr.com/7102/6999583228_99302b91ac_n.jpg');
@andykant

This comment has been minimized.

Show comment
Hide comment
@andykant

andykant Mar 20, 2013

Contributor

I was hoping #153's fix would knock this one out too as they seemed very related. No such luck but hopefully the solution with that bug will help with this one.

Contributor

andykant commented Mar 20, 2013

I was hoping #153's fix would knock this one out too as they seemed very related. No such luck but hopefully the solution with that bug will help with this one.

andykant added a commit that referenced this issue Mar 20, 2013

Added Mustache/EJS tests for Observe live binding issue #157
Observe properties added after initialization do not live update
properly in attributes

andykant added a commit that referenced this issue Mar 20, 2013

andykant added a commit that referenced this issue Mar 20, 2013

@andykant

This comment has been minimized.

Show comment
Hide comment
@andykant

andykant Mar 20, 2013

Contributor

What seems to be happening is that can.view.pending() doesn't update attributes when the attribute is being set in a nested block. The pending hookup for the nested block is created but not executed.

This works:

// <img src="<%== this.attr("image") %>" alt="An image" />
var ___v1ew = [];
___v1ew.push("<img src=\"");
___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
    return this.attr("image")
}));
___v1ew.push("\" alt=\"An image\" ", can.view.pending(), "/>");
___v1ew.push(can.view.txt(1, 'undefined', 0, this, function() {
    return this.attr("image")
}));;

So does this:

// <img src="<% { %><%== this.attr("image") %><% } %>" alt="An image" />
var ___v1ew = [];
___v1ew.push("<img src=\"");
___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
    var ___v1ew = []; {
        ___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
            return this.attr("image")
        }));
    };
    return ___v1ew.join('')
}));
___v1ew.push("\" alt=\"An image\" ", can.view.pending(), "/>");;

But this doesn't:

// <img <% { %>src="<%== this.attr("image") %>"<% } %> alt="An image" />
var ___v1ew = [];
___v1ew.push("<img ");
___v1ew.push(can.view.txt(0, 'img', 1, this, function() {
    var ___v1ew = []; {
        ___v1ew.push("src=\"");
        // The pending hookup this generates doesn't get created
        // until after the can.view.pending() later on.
        ___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
            return this.attr("image")
        }));
        ___v1ew.push("\"");
    };
    return ___v1ew.join('')
}));
___v1ew.push(" alt=\"An image\" ", can.view.pending(), "/>");
___v1ew.push(can.view.txt(1, 'undefined', 0, this, function() {
    return this.attr("image")
}));;
Contributor

andykant commented Mar 20, 2013

What seems to be happening is that can.view.pending() doesn't update attributes when the attribute is being set in a nested block. The pending hookup for the nested block is created but not executed.

This works:

// <img src="<%== this.attr("image") %>" alt="An image" />
var ___v1ew = [];
___v1ew.push("<img src=\"");
___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
    return this.attr("image")
}));
___v1ew.push("\" alt=\"An image\" ", can.view.pending(), "/>");
___v1ew.push(can.view.txt(1, 'undefined', 0, this, function() {
    return this.attr("image")
}));;

So does this:

// <img src="<% { %><%== this.attr("image") %><% } %>" alt="An image" />
var ___v1ew = [];
___v1ew.push("<img src=\"");
___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
    var ___v1ew = []; {
        ___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
            return this.attr("image")
        }));
    };
    return ___v1ew.join('')
}));
___v1ew.push("\" alt=\"An image\" ", can.view.pending(), "/>");;

But this doesn't:

// <img <% { %>src="<%== this.attr("image") %>"<% } %> alt="An image" />
var ___v1ew = [];
___v1ew.push("<img ");
___v1ew.push(can.view.txt(0, 'img', 1, this, function() {
    var ___v1ew = []; {
        ___v1ew.push("src=\"");
        // The pending hookup this generates doesn't get created
        // until after the can.view.pending() later on.
        ___v1ew.push(can.view.txt(0, 'img', 'src', this, function() {
            return this.attr("image")
        }));
        ___v1ew.push("\"");
    };
    return ___v1ew.join('')
}));
___v1ew.push(" alt=\"An image\" ", can.view.pending(), "/>");
___v1ew.push(can.view.txt(1, 'undefined', 0, this, function() {
    return this.attr("image")
}));;
@andykant

This comment has been minimized.

Show comment
Hide comment
@andykant

andykant Mar 21, 2013

Contributor

After some more research, we need a way to ensure that the can.view.txt calls are still initially executed (just not pushed into ___v1ew) regardless of potential surrounding logic. This might require significant changes to view/render and view/scanner.

Contributor

andykant commented Mar 21, 2013

After some more research, we need a way to ensure that the can.view.txt calls are still initially executed (just not pushed into ___v1ew) regardless of potential surrounding logic. This might require significant changes to view/render and view/scanner.

@andykant

This comment has been minimized.

Show comment
Hide comment
@andykant

andykant Mar 21, 2013

Contributor

Renamed the title of this issue to better describe it and prevent more duplicates.

Contributor

andykant commented Mar 21, 2013

Renamed the title of this issue to better describe it and prevent more duplicates.

@justinbmeyer

This comment has been minimized.

Show comment
Hide comment
@justinbmeyer

justinbmeyer Sep 21, 2013

Contributor

So, I made my own test and imported andy's and this is working in 1.2:

    var template = can.view.mustache('<img {{#image}}src="{{.}}"{{/image}} alt="An image" />'),
        data = new can.Map({
            image: null
        }),
        url = "http://canjs.us/scripts/static/img/canjs_logo_yellow_small.png";

    var frag = template(data),
        img = frag.childNodes[0];

    equal( img.hasAttribute('src'), false, "there is no src");

    data.attr("image",url)
    equal(img.hasAttribute('src'), true, 'Image should have src')
    equal( img.src, url, "images src is correct" );

This passes. So I'm closing this issue?

Contributor

justinbmeyer commented Sep 21, 2013

So, I made my own test and imported andy's and this is working in 1.2:

    var template = can.view.mustache('<img {{#image}}src="{{.}}"{{/image}} alt="An image" />'),
        data = new can.Map({
            image: null
        }),
        url = "http://canjs.us/scripts/static/img/canjs_logo_yellow_small.png";

    var frag = template(data),
        img = frag.childNodes[0];

    equal( img.hasAttribute('src'), false, "there is no src");

    data.attr("image",url)
    equal(img.hasAttribute('src'), true, 'Image should have src')
    equal( img.src, url, "images src is correct" );

This passes. So I'm closing this issue?

@justinbmeyer

This comment has been minimized.

Show comment
Hide comment
@justinbmeyer

justinbmeyer Sep 21, 2013

Contributor

We can open another issue that allows you to write this src="{image}", but this doesn't seem to be the focus of this issue.

Contributor

justinbmeyer commented Sep 21, 2013

We can open another issue that allows you to write this src="{image}", but this doesn't seem to be the focus of this issue.

@daffl daffl reopened this Oct 8, 2013

@daffl

This comment has been minimized.

Show comment
Hide comment
@daffl

daffl Oct 8, 2013

Contributor

This was what this issue is about. @andykant combined several similar issues into this one.

Contributor

daffl commented Oct 8, 2013

This was what this issue is about. @andykant combined several similar issues into this one.

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

hobbyquaker added a commit to hobbyquaker/DashUI that referenced this issue Mar 28, 2014

@sarathgalimelu

This comment has been minimized.

Show comment
Hide comment
@sarathgalimelu

sarathgalimelu Jul 13, 2017

Hello @andykant I was trying to use the img src as you mentioned in the workaround

<img {{#image}}src="{{.}}"{{/image}} alt="An image" />

This is my code what I have been trying to set the image src using a dataURI string to the template. But the src tag itself is not appended to the code after rendering the template. Can you help in this. Tried different combinations but didn't help. Working when the img src is a tag in my code.
Here is my code below and the version that I am using is 2.0

<a href="https://www.google.com/" style="font-family: 'Helvetica Neue', sans-serif; color: rgb(58, 139, 187); font-weight: normal; text-decoration: underline;" class="" target="_blank">
<img class="photo" width="200" src="{{ logoImage }}" id="headerImage" alt="Test Google" style="border: 0px; height: auto; line-height: 34px; outline: none; max-width: 600px !important;" />
</a>

sarathgalimelu commented Jul 13, 2017

Hello @andykant I was trying to use the img src as you mentioned in the workaround

<img {{#image}}src="{{.}}"{{/image}} alt="An image" />

This is my code what I have been trying to set the image src using a dataURI string to the template. But the src tag itself is not appended to the code after rendering the template. Can you help in this. Tried different combinations but didn't help. Working when the img src is a tag in my code.
Here is my code below and the version that I am using is 2.0

<a href="https://www.google.com/" style="font-family: 'Helvetica Neue', sans-serif; color: rgb(58, 139, 187); font-weight: normal; text-decoration: underline;" class="" target="_blank">
<img class="photo" width="200" src="{{ logoImage }}" id="headerImage" alt="Test Google" style="border: 0px; height: auto; line-height: 34px; outline: none; max-width: 600px !important;" />
</a>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment