I'm working on a jsPlumb problem. When I try to programatically remove all of an elements connections, I get Uncaught TypeError: Cannot read property 'left' of undefined
I have several "nodes" (html elements) that each have 1 input endpoint (an end point that accepts) and n output endpoints. Each node also has a javascript object behind it. I have a "selected" state in my software. Users can select multiple nodes and the objects are pushed to an array called selected. I have a key listener for the delete key. When the key is pressed it loops through selected nodes, deleting them and removing their endpoints. This works great when there are no connections, but when there are connections I the error.
The output endpoints are attached to child HTML elements of the main node…
There's a lot of code doing lots of stuff, but I'll try to share the relevant parts:
function Node(jsonFromServer){
/* … this is the constructor method… some code omitted*/
this.endpoints = [];
this.endpoints.push(jsPlumb.addEndpoint(this.el.attr("id"),targetEndpoint,{anchor:"TopCenter",uuid: this.el.attr("id") + "TopCenter"}));
this.addConnectionEndpoints();
}
Node.prototype.addConnectionEndPoints = function(){
//omitting code… loops through 'connections' that don't have 'has endpoint' marked….
this.endpoints.push(jsPlumb.addEndpoint(connection['el'].attr("id"),sourceEndpoint,{anchor:"RightMiddle",uuid:connection['el'].attr("id")+"RightMiddle"}));
connection.hasEndPoint = true;
}
So that was the setup. Here's how I delete
when key pressed
If key is delete /* all this stuff works */
loop through selected array (the array of selected Node elements:works)
node.el.hide(250).remove();
loop through node's endpoints array
//endpoint is the correct object... proved with console.log
//the following line is the error
jsPlumb.deleteEndpoint(endpoint);
ajax call to server to delete stuff on the backend
Fixed it! When I said node.el.hide(250).remove(); I removed an html element that was required in the delete process. I moved the remove part to the callback of the ajax request, and it works like a charm.
Related
I have a EditParentAndChildren screen where I want a test that:
navigates to page
remembers the name of the parent
pick one of the children rows
remember its id/name
delete it via the Trashcan button on that row
save
navigate to a View
ensure the parent's name appears and the deleted child's name does not
I can't seem to pluck text off of the screen and put it into one of Cypress's #alias variables, and standard js variables aren't allowed by cypress. So, I use .then to get the value that way.
But when I choose a child row and go .within to get its name and click its delete button, I can't then issue the final assertions for the test because I'm still in the .within, I can't escape the .within because the .then for getting the child's name is completely inside, and, trying to .root().closest() doesn't work because the <tr> I'm in is not only getting deleted but I'm doing a page nav afterward.
cy.get('[name=parentname]')
.invoke('val')
.then(parentName => {
cy.get('[class^=childrenTable]')
.find('[name=child_id]')
.first()
.parents('tr')
.within(tr => {
cy.get('[name=child_id]')
.invoke('val')
.then(nameOfchildToDelete => {
// delete this child
cy.get('[class*=trash]').click();
cy.get(loadingSpinner).should('not.exist');
// ERROR can't find submit button, you are still .within the <tr>
cy.contains(/Submit/i).click();
cy.url().should('match', /parent\/\d+$/);
cy.get(loadingSpinner).should('not.exist');
cy.contains('[class*=breadcrumb_currentcrumb]', parentName).should('exist');
cy.contains('table', nameOfChildToDelete).should('not.exist');
});
});
});
One solution is simply never to use .within. Formerly I was selecting the row, then within it selecting & using each piece of the row. Instead, select each piece of a row using the same selector that selects that row.
Not this:
cy.get('[class^=childrenTable]')
.find('[name=child_id]')
.first()
.parents('tr')
.within(tr => {
cy.get('[name=child_id]')
.invoke('val')
.then(nameOfchildToDelete => {
More like this:
cy.get('[class^=childrenTable] [name=sample_id]:first-child')
.invoke('val')
.then(nameOfSampleToDelete => {
// etc...
cy.get('[class^=childrenTable] [class*=trash]').first().click();
Code inside a .then is just like outside the .then excepting the level of indent, so most of the code is the same. But code inside a .within is kind of at a dead-end. You can't return values from a .within and can't set state or js vars from the outer context.
So: don't use .within, always use long selectors, and don't worry about picking "sections" like a particular <tr> or a particular card in a FlexBox for re-use.
If the selectors are very long consider moving them to a const string outside of the file and possibly concatting them if need be. But generally in Cypress trying to enter into a context is something of an anti-pattern.
I'm working on building a call center functionality that when receiving an inbound call, it dials through a list of agent's phone numbers (as determined by a separate piece of code) and on the first number connection we break out of the code and run a separate function to connect the agent into a queue where the customer is waiting. This is being built in Laravel 5.7 since there are some other future dashboards that are being created and I wanted to place it in the code the team is going to use.
The initial customer queueing and connecting the agent to the call seems to be working.
I am looking for help with the following code:
public function findAgentByPriority($agentCount) {
$twilio = new Client(env('TWILIO_SID'),env('TWILIO_SECRET'));
// test numbers
$agentArr[] = ["agent" => env('TWILIO_TEST_AGENT1')];
$agentArr[] = ["agent" => env('TWILIO_TEST_AGENT2')];
// $agentArr = json_encode($agentArr);
//build the array by querying /api/v1/agile/users
$numbers = $agentArr;
// this part of the code will call one person after the next
// call the next number
if($agentCount == NULL){
$agentCount = count($numbers);
echo "in if<br>";
$call = $twilio->calls
->create(
$numbers[0],
env('TWILIO_MAIN_NUMBER'),
[
"url" => "https://{$_SERVER['HTTP_HOST']}/ivr/connect-agent",
"statusCallback" => "https://{$_SERVER['HTTP_HOST']}/ivr/next-agent?c=$agentCount",
"timeout" => 20
]
);
}elseif($agentCount > 0){
// when we run out of numbers move out of the loop
$agentCount = 0;
}else{
// when we run out of numbers move out of the loop
}
// once there are no more agents that were logged in today we
// will move to dial cell phone fallback for 40s
// and last we'll call on the voicemail function
}
And here is our connectAgent function that the connect-agent route is calling.
public function connectAgent() {
$response = new Twiml\VoiceResponse;
$dequeue = $response->dial('');
$dequeue->queue('main');
}
I was thinking basically have the "statusCallback" shoot to a new method when we read that there was "no-answer" and call the next number in line. I don't know how to keep track of what numbers are left by passing a variable through the callback. Would setting it into a database be better and do something like look for any remaining arrayIDs where records still exist and dial down the next one? I could establish the array and it's parameters in the database on the first function call.
I could avoid the issue of two people calling at once and messing up the code by just building out different arrayIDs and only going through one set at a time.
Any guidance is appreciated!
UPDATE
PHP's server was causing infinite loops. Moving testing to my vagrant box has resolved this so now I can call on the Laravel route from the same server without issue. This along with the answer of passing an array through the callback has helped me solve this problem. Updated code to follow for reference.
this following issue helped me figure out the second request getting stuck issue: Calling route from same server causes an infinite loop
Twilio developer evangelist here.
What you could do is add the current number as a query parameter to the statusCallback URL. That way, when the callback is called you can find that number in your list of numbers and then move on to the next one. This way you don't need to store anything in the database.
Let me know if that helps at all.
I want to make 3 dependents drop down list, each drop down dependent to the previous drop down, so when I select an item from first drop down , all data fetch from database and add to second drop down as item.
I know how to do this in a normal php page using ajax, but as opencart uses MVC I don't know how can I get the selected value
Basically, you need two things:
(1) Handling list changes
Add an event handler to each list that gets its selected value when it changes (the part that you already know), detailed tutorial here in case someone needed it
Just a suggestion (for code optimization), instead of associating a separate JS function to each list and repeating the code, you can write the function once, pass it the ID of the changing list along with the ID of the depending list and use it anywhere.
Your HTML should look like
<select id="list1" onchange="populateList('list1', 'list2')">
...
</select>
<select id="list2" onchange="populateList('list2', 'list3')">
...
</select>
<select id="list3">
...
</select>
and your JS
function populateList(listID, depListID)
{
// get the value of the changed list thorugh fetching the elment with ID "listID"
var listValue = ...
// get the values to be set in the depending list through AJAX
var depListValues = ...
// populate the depending list (element with ID "depListID")
}
(2) Populating the depending list
Send the value through AJAX to the appropriate PHP function and get the values back to update the depending list (the part you are asking for), AJAX detailed tutorial here
open cart uses the front controller design patter for routing, the URL always looks like: bla bla bla.bla/index.php?route=x/y/z&other parameters, x = folder name that contains a set of class files, y = file name that contains a specific class, z = the function to be called in that class (if omitted, index() will be called)
So the answer for your question is:
(Step 1) Use the following URL in your AJAX request:
index.php?route=common/home/populateList
(Step 2) Open the file <OC_ROOT>/catalog/controller/common/home.php , you will find class ControllerCommonHome, add a new function with the name populateList and add your logic there
(Step 3) To use the database object, I answered that previously here
Note: if you are at the admin side, there is a security token that MUST be present in all links along with the route, use that URL:
index.php?route=common/home/populateList&token=<?php echo $this->session->data['token'] ?> and manipulate the file at the admin folder not the catalog
P.S: Whenever the user changes the selected value in list # i, you should update options in list # i + 1 and reset all the following lists list # i + 2, list # i + 3 ..., so in your case you should always reset the third list when the first list value is changed
P.P.S: A very good guide for OC 1.5.x => here (It can also be used as a reference for OC 2.x with some modifications)
I would like to display the count of validation errors to my user.
It is to implement a message like "You have X error(s) left" next to the submit button.
Is there a way to do this ?
Edit :
I am using ember-validations 2.0.0-alpha.1 and ember 1.8.0 in the context of a controller (without ember data).
If I try the solution of Sam:
this.get('errors.length') // result is [], an empty array
The errors key holds an object, not an array. Each key of this object refers to a property on your model and points to an array of error messages, so you can do things like this.get('errors.firstName.length').
To find the total number of errors, you'd have to look through each of your model's properties and sum the number of errors for each one.
http://emberjs.jsbin.com/luzesiyeqi/1/
EDIT:
The .length property of the errors object is returning an empty array because of this code: https://github.com/dockyard/ember-validations/blob/master/addon/errors.js. Literally any key you access on the errors object will be initialized to an empty array.
EDIT 2:
Based on what you said in the comments about not wanting to loop through properties, you can do it in an alternative fashion by looking at the model's validators property. Check out this example:
numErrors: function () {
var errorCounts = this.get('model.validators').mapBy('errors.length');
return errorCounts.reduce(function (a, b) { return a + b }, 0);
}.property('model.validators.#each.length')
I've updated the JSBin, too:
http://emberjs.jsbin.com/jucuxodaga/1/edit?html,js,output
If you're using ember-validations, this will be easy: this.errors.length.
I have an element like
<td class="google-visualization-table-th gradient google-visualization-table-sorthdr">
Project Name
<span class="google-visualization-table-sortind">▼</span>
</td>
I tried
driver.findElement(By.xpath("//td[contains(#class, 'google-visualization-table-th') and normalize-space(text()) = 'Project Name']")
But its not working. Basically its code for Column header and I need to recognize each column header and print if the heading exist or not.
We do not know which version of XPath you are using, but depending on the exact version, text() means different things.
I suspect that the text content of span(the weird character ▼) is also part of td/text(). This is because text() does not mean:
Return the rext nodes of the context node
In this case it means:
Return the text nodes of the context node and the text nodes of all its decendants.
Use contains() also in the second half of the predicate:
//td[contains(#class, 'google-visualization-table-th') and contains(.,'Project Name')]
Its resolved now, element was not getting identified because they were getting loaded in an iframe. I used the below code o switch to iframe and then did usual operations to track the elements.
WebDriverWait wait = new WebDriverWait(driver, 200);
By by = By.id("iframe id");
try {
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(by));
Thanks everyone for the help.