I'm new to Vue. I can not remove an item from a DOM, in Vue.js Javascript file.
I successfully managed to make an ajax post request, which removes a specific record from my database.
Once it's removed, I need to remove it from a DOM, so it won't shop up without need to reload the same page - I guess you know what I mean.
I can do it in jQuery, but I wonder how it should be done in Vue.js actually ?
Here is my portion of the code:
// SOME CODE BEFORE ...
onSubmit: function(e){
e.preventDefault();
$tablerow = this.el.parentNode.parentNode;
// Assign a correct submit request type and url
this.vm
.$http[this.getRequestType()](this.el.action)
.then(this.onComplete.bind(this))
.catch(this.onError.bind(this))
;
},
onComplete: function(){
// Remove the item from a DOM <<< I NEED TO REMOVE PARENT <tr/> ELEMENT
$(this.el).closest('tr').fadeOut(300, function(){
this.remove();
});
// If complete message exists, use it as a feedback
if(this.params.complete){
alert(this.params.complete);
}
},
// SOME CODE AFTER ...
Any suggestion please ? Sorry if my question is dumb, but I have not best knowledge in programming.
Normally you will have a list of items you are displaying with v-for in your table rows which are stored in an array. After your ajax call you can remove this item using this.items.$remove(item) and it will be automatically removed from where it is displayed in the DOM.
Since you didn't show your template I will try to recreate a similar scenario of what i think you are trying to do
data: function(){
return {
items: ['item1','item2','item3']
}
},
methods: {
remove: function(item){
ajaxCall.then(function(){
this.items.$remove(item);//will remove the <tr> from the DOM
});
}
}
Your template can be like
<tbody>
<tr v-for="item in items" v-on:click="remove(item)">{{ item }}</tr>
</tbody>
Related
i interested in learn how to correctly add .bind code to object, then he changed. This object is not unic and have class selector insted of id, but it have a <div> wrapper:
<div id="GDI">
<table class = "Tiberium">
...
<tbody>
<tr>...</tr>
...
<tr>...</tr>
</tbody>
</table>
</div>
<div id="NOD">
<table class = "Tiberium">
...
<tbody>
<tr>...</tr>
...
<tr>...</tr>
</tbody>
</table>
</div>
The data changed in table with class "Tiberium" in <tbody> space (e.g. was added new row), i need simple alert then data changed in GDI table, but dont know how to do it.
Code that i tried:
$('.Tiberium').bind('DOMSubtreeModified', Alert);
Where Alert is function.
This code capture changes in both tables, and i got alerts then one of them changed. So how i can track changes only in "Tiberium" table in GDI space?
p.s. i'v tried $('#NOD').bind('DOMSubtreeModified', Alert);
but this code alert me 3 times in row, and it possible run every code in function 3 times. (i think it happend in case of this hierarchy).
The DOMSubTreeModified event is deprecated. A better alternative to this solution is to use the MutationObserver.
var toBeObserved = document.getElementsByClassName('Tiberium');
if('MutationObserver' in window) { // ensure browser support
var observer = new MutationObserver(myEventHandler); // instantiate
observer.observe(toBeObserved, { // start observing
childList : true,
subtree : true
});
}
Everytime the toBeObserved element is mutated, the myEventHandler function will be called. You can add your custom code within this function.
Could you please try following code:
$('.Tiberium').bind('DOMSubtreeModified', function(){
//check the parent div's id
if($(this).parent().attr("id") == "GDI")
Alert //your alert function call
});
I have the following Dojo Javascript snippet:
postCreate: function () {
this.inherited(arguments);
var hitchWidgetToaddLevelButtonClickHandler = DojoBaseLang.hitch(this, addLevelButtonClickHandler);
DojoOn(this.AddLevelButton, "click", hitchWidgetToaddLevelButtonClickHandler);
function addLevelButtonClickHandler() {
hierarchyLevelNumber += 1;
var myButton = new Button({
label: "Click me!",
id: "level_button_" + hierarchyLevelNumber,
onClick: function(){
// Do something:
console.log("Hello there, ");
}
}).placeAt(someNode,"last").startup();
var registeredRemovalButton = DijitRegistry.byId(("level_button_" + hierarchyLevelNumber));
DojoOn(registeredRemovalButton, "click", function someFunction() {
console.log("how are you?");
});
}
}
and the following HTML
<div id="settingsBorderContainer" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline', gutters:false, region:'top'" class="${theme}">
<table data-dojo-attach-point="HierarchyLevelsTable">
<tr>
<th>Level</th>
<th> Table Name </th>
<th> Column Name</th>
</tr>
<td id="someNode">
</td>
</table>
</div>
The goal here is, when AddLevelButton is clicked it dynamically creates a row in the table with the necessary information and a new button for each row. Note that the HTML and Javascript are largely simplified to illustrate my problem. I did not include all of the row logic that occurs in addLevelButtonClickHandler() method. The HTMl is built as intended, as you can see in the following screenshot:
The problem is that everytime I add a button, only the last button's event listeners work, i.e. in the case of the screenshot the button circled in red logs: Hello there, you called the remove handler [object MouseEvent], and the previous button in the table no longer can be clicked and catch the necessary event. Sorry if the code is a gross-simplification of my goal, I appreciate any help that is offered.
*********EDIT**************
So I took a different approach and placed only 1 button total, and delete level by level from the bottom up. As long as it resides outside of a <table> it functions..Which brings me to the conclusion of NEVER PUT DIJITS OR BUTTONS IN A TABLE After many hours lost, I would recommend if you absolutely need a table in the first place, just placing the button next to the table as necessary using CSS and floats
I will leave this question as unanswered until someone may be able to offer an explanation of why the inner table approach does not work.
While working with dojo. You should never use node.innerHTML to add or update nodes. It will basically convert all the dijits into HTML string and parse as regular HTML by the browser. which in turn will destroy dom object and event associated to it.
Instead create dom object using dojo/dom-construct and add it with appendChild for DOM nodes or addChild in case of container dijits.
I need to make a data table for an enyo project I am working on that will ultimately display the result of an Ajax call.
This (Blatantly stolen from ryanjduffy here)seems to be a good starting point, but when I try to call setData() from a button event (rather than in the constructor) as I have here I get the following error:
InvalidCharacterError: String contains an invalid character # http://enyojs.com/enyo-2.1/enyo/source/dom/Control.js:681
I looked at the Control.js code and it seems that it tries to create a new node, but the this.tag property is set to null and things break.
I feel like I am missing something really simple, but I just can't see the problem yet...
Can someone tell me what I am doing wrong?
Thanks!
EDIT 1:
Apparently calling render() is not needed. Here is the original working version with render() commented out. Everything looks great. However, if I try to remove render() from the version that requires a button click, the repeater starts creating div's above the table instead of tr td's inside the table...
EDIT 2:
Basically, from what I can tell, the Repeater inside of a table will lose it's parent once the table is rendered (or something like that). The result is the Repeater will start rendering its new items outside of the original table and because a td tag without a table makes no sense, it just renders a div.
The solution I have come up with is to give the Repeater itself a table tag so its children always wind up in the right spot. This adds the challenge of needing to recreate the header line each time, but it is not that big of a deal. I have a working example if anyone is interested.
I'm sure you're not looking for a solution any longer but since I was mentioned in the post, I thought I'd let you know what I figured out. In short, my code shouldn't have worked but since browsers are forgiving, it did ... sort of.
When the code run at create time, it renders something like this:
<table>
<tr> <!-- header row --> </tr>
<div> <!-- repeater tag -->
<tr> <!-- repeater row --> </tr>
</div>
</table>
The browser looks at that and says, "Hey, dummy! No <div>s in a <table>" and kicks it out but leaves the <tr>s.
In your example, since you're delaying the render of the rows, Enyo renders:
<table>
<tr> <!-- header row --> </tr>
<div></div>
</table>
And the browser ejects the <div> and you're left with an empty table. When you later set the data, those rows are rendered into the div. Unfortunately, since you're rendering <tr> and <td>, those aren't valid outside a table so you just get text.
I found a couple solutions. The simplest was to set the tag of the Repeater to be TBODY which is allowed inside a table. The slightly more involved solution was to make the DataTable inherit from Repeater and set the header row to be chrome so they're not removed when updating the data.
Option #2 Fiddle
enyo.kind({
name:"DataTable",
tag: "table",
kind: "Repeater",
published:{
map:0,
data:0
},
handlers: {
onSetupItem: "setupItem"
},
components:[
{name:"row", kind:"DataRow"}
],
create:function() {
this.inherited(arguments);
this.mapChanged = this.dataChanged = enyo.bind(this, "refresh");
this.refresh();
},
refresh:function() {
if(this.map && this.data) {
this.buildHeader();
this.setCount(this.data.length);
}
},
buildHeader:function() {
if(this.$.header) {
this.$.header.destroyClientControls();
} else {
this.createComponent({name:"header", tag:"tr", isChrome: true});
}
for(var i=0;i<this.map.length;i++) {
this.$.header.createComponent({content:this.map[i].header, tag:"th"});
}
this.$.header.render();
},
setupItem:function(source, event) {
for(var i=0;i<this.map.length;i++) {
event.item.$.row.createComponent({content:this.data[event.index][this.map[i].field]});
}
event.item.render();
return true;
}
});
I have this code working but wondering if I'm doing it the long way. Is there a more efficient way? I was hoping for a 1 line of code solution.
I want to change the color of a single DIV in a table created from a {{#each}} in Handlebars template. I came up with this callback, so every time isSharedByMe (which is a field in a Collection) becomes true, the templates reactivity sets the CSS color to green:
Template.showRepost.rendered = function () {
if (this.data.isSharedByMe) {
$( this.find('.repost') ).css( {'color': 'green'} );
}
return; // I like to explicitly show a return value so people know
// I'm not returning any specific value on purpose.
// Not sure if this kills efficiency (separate topic).
};
The Handlebars template is simple, I call this as a partial from my main template that has the {{#each posts}} call which produces the table:
<template name="showRepost">
{{show_repost_txt}}
</template>
{{show_repost_txt}} just shows returns text like, "Share", or "Already Shared".
This code above works, but what I was hoping for was to have 1 jQuery type line in my show_repost_txt helper to set the CSS color at the same time as changing text to "Already Shared".
But I could figure out how to set ONLY the current class .repost, since this.find is not available in custom template helpers, but is available in the .rendered callback (along with event handlers). I tried this jQuery with no luck:
Template.showRepost.show_repost_txt = function () {
if (this.isSharedByMe) {
// Type $(this) in the Browser console
// (it's the jQuery call to the DOM window object,
// I just can't figure out how to get the specific DIV I need.
$(this).find('.repost').css( {'color': 'green'} );
return "Already shared.";
}
};
Can you just make the css tag reactive like this?
<template name="showRepost">
{{show_repost_txt}}
</template>
and then add this to your css:
// Returns any extra classes to be applied to the link
Template.showRepost.extraClasses = function () {
if (this.data.isSharedByMe) {
return "theColorGreen"; // you will also need to add a 'theColorGreen' class to your .css file that matches this
}
return "";
};
I have the following markup:
<button dojoType="dijit.form.DropDownButton" dojoAttachPoint="labels" label="Labels">
<div dojoType="dijit.Menu" dojoAttachPoint="labelsMenu"></div>
</button>
I am adding MenuItems programatically and it works fine for the first time. But when I want to refresh I get an error: Tried to register widget with id==16 but that id is already registered. I have tried the following code to clear but it's not working:
var labels = dijit.findWidgets(this.labels);
dojo.forEach(labels, function (l) {
l.destroyRecursive();
});
dojo.empty(dojo.byId(this.labels));
I have also try the same thing for labelsMenu to empty it but no luck. Is there any other way to get rid of all children when reloading data or am missing something?
I have solved it and here's what I did:
var menuChildren = dijit.byId(this.labelsMenu).getChildren();
if (menuChildren.length > 0){
dojo.forEach(menuChildren, function(mc){
mc.destroyRecursive();
});
}
In your code you call dojo.empty on the labels. dojo.empty() empties the element in the DOM but keeps the original element. So try calling dojo.empty on the dijit menu instead.
dojo.empty(dojo.byId("labelsMenu"));
For reference, in a fully baseless application, the dom-construct module is used.
require(["dojo/dom-construct"], function(domConstruct){
// Empty node's children byId:
domConstruct.empty("someId");
});